Bug Report Checklist
Description
The dart generator calls .toUtc() on format: date fields before formatting them, and that shifts the date one day back in any UTC+X timezone.
_dateFormatter is DateFormat('yyyy-MM-dd'), which just formats whatever y/m/d the DateTime already carries. It does no timezone conversion. So the .toUtc() there does nothing except roll the clock back past midnight before the date is read.
Going the other way, mapDateTime parses the bare wire value "2026-09-12" with DateTime.tryParse, which gives you local midnight. Round trip in Oslo:
"2026-09-12" -> DateTime 2026-09-12 00:00 local -> toUtc() 2026-09-11 22:00Z -> "2026-09-11"
It is stable in UTC, which I bet is why nobody noticed. We only found it because a payment deadline got printed one day early on a physical parking fine, and a read-modify-write on the same field walked the stored date one day earlier on every save.
FWIW dart-dio already handles this correctly with its own Date class (plain year/month/day ints, no DateTime), so the two dart generators disagree today.
openapi-generator version
Reproduced on master (66f6973, 2026-08-13). Also present in 7.19 and 7.24, so not a regression, looks like it has been there a long time.
OpenAPI declaration file content or url
openapi: 3.0.0
info:
title: Date only
version: 1.0.0
paths: {}
components:
schemas:
DateOnlyModel:
type: object
required:
- requiredDate
properties:
requiredDate:
type: string
format: date
Generation Details
openapi-generator-cli generate \
-i spec.yaml \
-g dart \
-o out
Steps to reproduce
- Generate with the spec above.
- Look at
out/lib/model/date_only_model.dart:
json[r'requiredDate'] = _dateFormatter.format(this.requiredDate.toUtc());
- Round trip a value with
TZ=Europe/Oslo:
final parsed = mapDateTime({'requiredDate': '2026-09-12'}, 'requiredDate', '');
print(DateOnlyModel(requiredDate: parsed!).toJson()['requiredDate']);
Actual: 2026-09-11
Expected: 2026-09-12
With TZ=UTC you get 2026-09-12, so it only shows up east of UTC. West of UTC it is fine at midnight, but a non-midnight value shifts forward a day.
Related issues/PRs
Could not find one for dart. Same bug class has been reported for other generators, at least #24635 and #12490 (both typescript-fetch).
Suggest a fix
Drop the .toUtc() from the four {{#isDate}} sites in dart2/serialization/native/native_class.mustache (lines 85, 88, 123, 126 on master). The {{#isDateTime}} branch right next to it should keep it, an instant genuinely needs UTC, a calendar date does not.
Should be safe both ways: toUtc() returns this when the DateTime is already UTC, so for UTC callers removing it is a no-op, and for local callers it removes a wrong shift.
I have a fix with a regression test and regenerated samples ready, will open a PR shortly.
Bug Report Checklist
Description
The
dartgenerator calls.toUtc()onformat: datefields before formatting them, and that shifts the date one day back in any UTC+X timezone._dateFormatterisDateFormat('yyyy-MM-dd'), which just formats whatever y/m/d the DateTime already carries. It does no timezone conversion. So the.toUtc()there does nothing except roll the clock back past midnight before the date is read.Going the other way,
mapDateTimeparses the bare wire value"2026-09-12"withDateTime.tryParse, which gives you local midnight. Round trip in Oslo:It is stable in UTC, which I bet is why nobody noticed. We only found it because a payment deadline got printed one day early on a physical parking fine, and a read-modify-write on the same field walked the stored date one day earlier on every save.
FWIW
dart-dioalready handles this correctly with its ownDateclass (plain year/month/day ints, no DateTime), so the two dart generators disagree today.openapi-generator version
Reproduced on master (
66f6973, 2026-08-13). Also present in 7.19 and 7.24, so not a regression, looks like it has been there a long time.OpenAPI declaration file content or url
Generation Details
Steps to reproduce
out/lib/model/date_only_model.dart:TZ=Europe/Oslo:Actual:
2026-09-11Expected:
2026-09-12With
TZ=UTCyou get2026-09-12, so it only shows up east of UTC. West of UTC it is fine at midnight, but a non-midnight value shifts forward a day.Related issues/PRs
Could not find one for dart. Same bug class has been reported for other generators, at least #24635 and #12490 (both typescript-fetch).
Suggest a fix
Drop the
.toUtc()from the four{{#isDate}}sites indart2/serialization/native/native_class.mustache(lines 85, 88, 123, 126 on master). The{{#isDateTime}}branch right next to it should keep it, an instant genuinely needs UTC, a calendar date does not.Should be safe both ways:
toUtc()returnsthiswhen the DateTime is already UTC, so for UTC callers removing it is a no-op, and for local callers it removes a wrong shift.I have a fix with a regression test and regenerated samples ready, will open a PR shortly.