89 lines
2.5 KiB
Dart
89 lines
2.5 KiB
Dart
class ShanghaiTime {
|
|
ShanghaiTime._();
|
|
|
|
static const offset = Duration(hours: 8);
|
|
|
|
/// A device-timezone-independent civil clock for Asia/Shanghai.
|
|
static DateTime get now => toCivil(DateTime.now());
|
|
|
|
static DateTime toCivil(DateTime instant) {
|
|
final shifted = instant.toUtc().add(offset);
|
|
return DateTime(
|
|
shifted.year,
|
|
shifted.month,
|
|
shifted.day,
|
|
shifted.hour,
|
|
shifted.minute,
|
|
shifted.second,
|
|
shifted.millisecond,
|
|
shifted.microsecond,
|
|
);
|
|
}
|
|
|
|
static DateTime civilToUtc(DateTime civil) => DateTime.utc(
|
|
civil.year,
|
|
civil.month,
|
|
civil.day,
|
|
civil.hour,
|
|
civil.minute,
|
|
civil.second,
|
|
civil.millisecond,
|
|
civil.microsecond,
|
|
).subtract(offset);
|
|
|
|
/// Parses API/cache instants. Legacy values without a zone were stored as UTC.
|
|
static DateTime parseUtcInstant(String value) {
|
|
final parsed = DateTime.parse(value);
|
|
if (value.endsWith('Z') || RegExp(r'[+-]\d{2}:?\d{2}$').hasMatch(value)) {
|
|
return parsed.toUtc();
|
|
}
|
|
return DateTime.utc(
|
|
parsed.year,
|
|
parsed.month,
|
|
parsed.day,
|
|
parsed.hour,
|
|
parsed.minute,
|
|
parsed.second,
|
|
parsed.millisecond,
|
|
parsed.microsecond,
|
|
);
|
|
}
|
|
|
|
static DateTime parseCivil(String value) => toCivil(parseUtcInstant(value));
|
|
|
|
static DateTime startOfDayUtc(DateTime civil) =>
|
|
civilToUtc(DateTime(civil.year, civil.month, civil.day));
|
|
|
|
static ({DateTime start, DateTime end}) monthRangeUtc(int year, int month) =>
|
|
(
|
|
start: civilToUtc(DateTime(year, month, 1)),
|
|
end: civilToUtc(DateTime(year, month + 1, 1)),
|
|
);
|
|
|
|
static ({DateTime start, DateTime end}) yearRangeUtc(int year) => (
|
|
start: civilToUtc(DateTime(year, 1, 1)),
|
|
end: civilToUtc(DateTime(year + 1, 1, 1)),
|
|
);
|
|
|
|
static ({DateTime start, DateTime end}) weekRangeUtc(DateTime civil) {
|
|
final date = DateTime(civil.year, civil.month, civil.day);
|
|
final start = date.subtract(Duration(days: date.weekday - DateTime.monday));
|
|
return (
|
|
start: civilToUtc(start),
|
|
end: civilToUtc(start.add(const Duration(days: 7))),
|
|
);
|
|
}
|
|
|
|
static String formatCivil(DateTime value) =>
|
|
'${value.year.toString().padLeft(4, '0')}-'
|
|
'${value.month.toString().padLeft(2, '0')}-'
|
|
'${value.day.toString().padLeft(2, '0')} '
|
|
'${value.hour.toString().padLeft(2, '0')}:'
|
|
'${value.minute.toString().padLeft(2, '0')}';
|
|
|
|
static String formatDateTime(DateTime instant) {
|
|
final value = toCivil(instant);
|
|
return formatCivil(value);
|
|
}
|
|
}
|