Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
RFC3339 DateTime Serializer
class DateTimeSerializer {
static DateTime? deserialize(String? serialized) {
if (serialized == null) return null;
final serializedString = serialized;
final fixed = serializedString.replaceAllMapped(
RegExp(r'(.*:\d\d)(\.\d+)?(Z|[+-]\d{2}:\d{2})'),
(match) {
// #1 capturing group is date and time without a fraction of a second
// #2 group is `time-secfrac` - if present
// #3 group is `time-offset`
var timeSecfrac = match[2] ?? '';
if (timeSecfrac.length > 7) {
// 6 is 0th period + (up to) 6 characters accepted by ISO8601
timeSecfrac = timeSecfrac.substring(0, 7);
}
return (match[1] ?? '') + timeSecfrac + (match[3] ?? '');
},
);
return DateTime.parse(fixed).toUtc();
}
static String? serialize(DateTime? dateTime) {
// if (!dateTime.isUtc) {
// throw ArgumentError.value(dateTime, 'dateTime', 'Must be in utc for serialization.');
// }
if (dateTime == null) return null;
if (!dateTime.isUtc) {
final utc = dateTime.toUtc();
return DateTime.utc(
utc.year, utc.month, utc.day, utc.hour, utc.minute, utc.second, utc.millisecond, utc.microsecond)
.toIso8601String();
}
return dateTime.toIso8601String();
}
}
import 'package:test/test.dart';
void main() {
test('correctly parses RFC 3339 dates', () {
final cases = {
// ISO 8601
'2019-08-09T06:55:01.896826+05:00': DateTime.utc(2019, 8, 9, 1, 55, 1, 896, 826),
'2019-08-09T06:55:01.896826Z': DateTime.utc(2019, 8, 9, 6, 55, 1, 896, 826),
'2019-08-09T06:55:01Z': DateTime.utc(2019, 8, 9, 6, 55, 1),
// RFC 3339
'2019-05-31T10:35:45.347333481Z': DateTime.utc(2019, 5, 31, 10, 35, 45, 347, 333),
'2018-01-29T18:39:51.396781283+01:00': DateTime.utc(2018, 1, 29, 17, 39, 51, 396, 781),
'2019-08-09T06:55:01.8968264+00:00': DateTime.utc(2019, 8, 9, 6, 55, 1, 896, 826),
'2020-10-20T20:55:01+09:00': DateTime.utc(2020, 10, 20, 11, 55, 1, 0, 0),
'2020-10-20T20:35+09:00': DateTime.utc(2020, 10, 20, 11, 35, 0, 0, 0),
};
cases.forEach((source, datetime) {
final deserialized = DateTimeSerializer.deserialize(source);
print('source :$source');
print('datetime :$datetime');
print('deserialized:$deserialized');
print(' tz :${deserialized?.timeZoneName}');
print(' offset:${deserialized?.timeZoneOffset}');
print(' local :${deserialized?.toLocal()}');
expect(deserialized, datetime);
final serialized = DateTimeSerializer.serialize(deserialized);
print('serialized :$serialized');
print('');
});
final now = DateTime.now();
print('source :$now');
final serializedNow = DateTimeSerializer.serialize(now);
print('serializedNow :$serializedNow');
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment