Last active
March 20, 2025 15:54
-
-
Save PlugFox/a94be8655b2adb91336f03bc77513d76 to your computer and use it in GitHub Desktop.
DateTime to int, Date and Time extension
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ignore_for_file: avoid_print | |
/* | |
* Date <==> Int conversion | |
* https://gist.github.com/PlugFox/a94be8655b2adb91336f03bc77513d76 | |
* https://dartpad.dev?id=a94be8655b2adb91336f03bc77513d76 | |
* Mike Matiunin <[email protected]>, 20 March 2025 | |
*/ | |
/// Date extension type | |
extension type const Date._(DateTime _date) implements DateTime { | |
/// Create Date from [year], [month] and [day] | |
Date(int year, int month, int day) : _date = DateTime.utc(year, month, day); | |
/// Get current Date | |
factory Date.now() => Date.of(DateTime.now()); | |
/// Create Date from [date] | |
factory Date.of(DateTime date) { | |
final DateTime(:year, :month, :day) = date.toUtc(); | |
return Date(year, month, day); | |
} | |
/// Create Date from [value] | |
Date.value(int value) | |
: _date = DateTime.utc( | |
value >> 9, // year (12 bit) | |
(value >> 5) & 0xF, // month (4 bit) | |
value & 0x1F, // day (5 bit) | |
); | |
/// Get Date as value | |
int get value => | |
(_date.year << 9) | // YYYYYYYYYYYY (0–4095) | |
(_date.month << 5) | // MMMM (1–12) | |
_date.day; // DDDDD (1–31) | |
/// Get Date as representation YYYY-MM-DD | |
String get representation => | |
'${year.toString().padLeft(4, '0')}-' | |
'${month.toString().padLeft(2, '0')}-' | |
'${day.toString().padLeft(2, '0')}'; | |
} | |
/// Time extension type | |
extension type const Time._(DateTime _time) implements DateTime { | |
/// Create Time from [hour], [minute] and [second] | |
Time(int hour, int minute, int second) | |
: _time = DateTime.utc(0, 1, 1, hour, minute, second); | |
/// Get current time | |
factory Time.now() => Time.of(DateTime.now()); | |
/// Create Time from [time] | |
factory Time.of(DateTime time) { | |
final DateTime(:hour, :minute, :second) = time.toUtc(); | |
return Time(second, minute, second); | |
} | |
/// Create Date from [value] | |
Time.value(int value) | |
: _time = DateTime.utc( | |
0, | |
1, | |
1, | |
(value >> 12) & 0x1F, // Hours (5 bit) | |
(value >> 6) & 0x3F, // Minutes (6 bit) | |
value & 0x3F, // Seconds (6 bit) | |
); | |
/// Get Time as value | |
int get value => | |
(_time.hour << 12) | // HHHHH (0–23) | |
(_time.minute << 6) | // MMMMMM (0–59) | |
_time.second; // SSSSSS (0–59) | |
/// Get Date as representation HH:MM:SS | |
String get representation => | |
'${hour.toString().padLeft(2, '0')}:' | |
'${minute.toString().padLeft(2, '0')}:' | |
'${second.toString().padLeft(2, '0')}'; | |
} | |
void main() { | |
void expect(DateTime a, DateTime b) { | |
final $a = a.millisecondsSinceEpoch, $b = b.millisecondsSinceEpoch; | |
if ($a == $b) return; | |
throw Exception('${a.toUtc()} != ${b.toUtc()}'); | |
} | |
final dates = [ | |
DateTime.utc(0), | |
DateTime.utc(2021, 1, 1), | |
DateTime.utc(2024, 10, 10), | |
DateTime.utc(5000, 12, 30), | |
]; | |
for (final dt in dates) { | |
final date = DateTime.utc(dt.year, dt.month, dt.day); | |
// Check conversion date to value and back | |
expect(Date.value(Date.of(date).value), date); | |
print('$date => ${Date.of(dt).value}'); | |
// Check how compact is the value | |
final DateTime(:year, :month, :day) = dt; | |
final text = [ | |
year, | |
month, | |
day, | |
].map((e) => e.toString().padLeft(2, '0')).join(''); | |
if (text.length < Date.of(dt).value.toString().length) { | |
throw Exception('$text is more compact than ${Date.of(dt).value}'); | |
} | |
} | |
// 5 Mar. 2025 | |
print(Date.of(DateTime.utc(2025, 03, 05)).value); // 1036901 | |
print(Date.value(1036901).representation); // 5 Mar. 2025 | |
// 12:34:56 | |
print(Time.of(DateTime.utc(0, 0, 0, 12, 34, 56)).value); // 51384 | |
print(Time.value(51384).representation); // 12:34:56 | |
} |
@arxdeus it's unsafe to use conversion to DateTime with seconds at web.
Because its int limited to value 2^53 – 1.
We should not include seconds in that conversion or store time separately from the date.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
problem with years in web
