745f112ef6
Opt an initial batch of files under samples, samples-dev, utils, and runtime/tools/dartfuzz out of null safety in preparation for switching the flag on by default. Change-Id: Icdfd52a5a969e678a7205903332f73fe3841c223 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/166960 Reviewed-by: Daco Harkes <dacoharkes@google.com> Commit-Queue: Leaf Petersen <leafp@google.com>
211 lines
5.9 KiB
Dart
211 lines
5.9 KiB
Dart
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// @dart = 2.9
|
|
|
|
part of utilslib;
|
|
|
|
/**
|
|
* General purpose date/time utilities.
|
|
*/
|
|
class DateUtils {
|
|
// TODO(jmesserly): localized strings
|
|
static const WEEKDAYS = const [
|
|
'Monday',
|
|
'Tuesday',
|
|
'Wednesday',
|
|
'Thursday',
|
|
'Friday',
|
|
'Saturday',
|
|
'Sunday'
|
|
];
|
|
|
|
static const YESTERDAY = 'Yesterday';
|
|
|
|
static const MS_IN_WEEK = DateTime.daysPerWeek * Duration.millisecondsPerDay;
|
|
|
|
// TODO(jmesserly): workaround for missing DateTime.fromDate in Dartium
|
|
// Remove this once that is implemented. See b/5055106
|
|
// Parse a string like: "Mon, 27 Jun 2011 15:22:00 -0700"
|
|
static DateTime fromString(String text) {
|
|
final parts = text.split(' ');
|
|
if (parts.length == 1) {
|
|
return _parseIsoDate(text);
|
|
}
|
|
|
|
if (parts.length != 6) {
|
|
throw 'bad date format, expected 6 parts: $text';
|
|
}
|
|
|
|
// skip parts[0], the weekday
|
|
|
|
int day = int.parse(parts[1]);
|
|
|
|
final months = const [
|
|
'Jan',
|
|
'Feb',
|
|
'Mar',
|
|
'Apr',
|
|
'May',
|
|
'Jun',
|
|
'Jul',
|
|
'Aug',
|
|
'Sep',
|
|
'Oct',
|
|
'Nov',
|
|
'Dec'
|
|
];
|
|
int month = months.indexOf(parts[2], 0) + 1;
|
|
if (month < 0) {
|
|
throw 'bad month, expected 3 letter month code, got: ${parts[2]}';
|
|
}
|
|
|
|
int year = int.parse(parts[3]);
|
|
|
|
final timeParts = parts[4].split(':');
|
|
if (timeParts.length != 3) {
|
|
throw 'bad time format, expected 3 parts: ${parts[4]}';
|
|
}
|
|
|
|
int hours = int.parse(timeParts[0]);
|
|
int minutes = int.parse(timeParts[1]);
|
|
int seconds = int.parse(timeParts[2]);
|
|
|
|
// TODO(jmesserly): TimeZone is not implemented in Dartium. This ugly
|
|
// hack applies the timezone from the string to the final time
|
|
int zoneOffset = int.parse(parts[5]) ~/ 100;
|
|
|
|
// Pretend it's a UTC time
|
|
DateTime result =
|
|
new DateTime.utc(year, month, day, hours, minutes, seconds, 0);
|
|
// Shift it to the proper zone, but it's still a UTC time
|
|
result = result.subtract(new Duration(hours: zoneOffset));
|
|
// Then render it as a local time
|
|
return result.toLocal();
|
|
}
|
|
|
|
/** Parse a string like: 2011-07-19T22:03:04.000Z */
|
|
// TODO(jmesserly): workaround for DateTime.fromDate, which has issues:
|
|
// * on Dart VM it doesn't handle all of ISO 8601. See b/5055106.
|
|
// * on DartC it doesn't work on Safari. See b/5062557.
|
|
// Remove this once that function is fully implemented
|
|
static DateTime _parseIsoDate(String text) {
|
|
void ensure(bool value) {
|
|
if (!value) {
|
|
throw 'bad date format, expected YYYY-MM-DDTHH:MM:SS.mmmZ: $text';
|
|
}
|
|
}
|
|
|
|
bool isUtc = text.endsWith('Z');
|
|
if (isUtc) {
|
|
text = text.substring(0, text.length - 1);
|
|
}
|
|
|
|
final parts = text.split('T');
|
|
ensure(parts.length == 2);
|
|
|
|
final date = parts[0].split('-');
|
|
ensure(date.length == 3);
|
|
|
|
final time = parts[1].split(':');
|
|
ensure(time.length == 3);
|
|
|
|
final seconds = time[2].split('.');
|
|
ensure(seconds.length >= 1 && seconds.length <= 2);
|
|
int milliseconds = 0;
|
|
if (seconds.length == 2) {
|
|
milliseconds = int.parse(seconds[1]);
|
|
}
|
|
|
|
return new DateTime(
|
|
int.parse(date[0]),
|
|
int.parse(date[1]),
|
|
int.parse(date[2]),
|
|
int.parse(time[0]),
|
|
int.parse(time[1]),
|
|
int.parse(seconds[0]),
|
|
milliseconds);
|
|
}
|
|
|
|
/**
|
|
* A date/time formatter that takes into account the current date/time:
|
|
* - if it's from today, just show the time
|
|
* - if it's from yesterday, just show 'Yesterday'
|
|
* - if it's from the same week, just show the weekday
|
|
* - otherwise, show just the date
|
|
*/
|
|
static String toRecentTimeString(DateTime then) {
|
|
bool datesAreEqual(DateTime d1, DateTime d2) {
|
|
return (d1.year == d2.year) &&
|
|
(d1.month == d2.month) &&
|
|
(d1.day == d2.day);
|
|
}
|
|
|
|
final now = new DateTime.now();
|
|
if (datesAreEqual(then, now)) {
|
|
return toHourMinutesString(new Duration(
|
|
days: 0,
|
|
hours: then.hour,
|
|
minutes: then.minute,
|
|
seconds: then.second,
|
|
milliseconds: then.millisecond));
|
|
}
|
|
|
|
final today = new DateTime(now.year, now.month, now.day, 0, 0, 0, 0);
|
|
Duration delta = today.difference(then);
|
|
if (delta.inMilliseconds < Duration.millisecondsPerDay) {
|
|
return YESTERDAY;
|
|
} else if (delta.inMilliseconds < MS_IN_WEEK) {
|
|
return WEEKDAYS[getWeekday(then)];
|
|
} else {
|
|
// TODO(jmesserly): locale specific date format
|
|
String twoDigits(int n) {
|
|
if (n >= 10) return "${n}";
|
|
return "0${n}";
|
|
}
|
|
|
|
String twoDigitMonth = twoDigits(then.month);
|
|
String twoDigitDay = twoDigits(then.day);
|
|
return "${then.year}-${twoDigitMonth}-${twoDigitDay}";
|
|
}
|
|
}
|
|
|
|
// TODO(jmesserly): this is a workaround for unimplemented DateTime.weekday
|
|
// Code inspired by v8/src/date.js
|
|
static int getWeekday(DateTime dateTime) {
|
|
final unixTimeStart = new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
|
int msSince1970 = dateTime.difference(unixTimeStart).inMilliseconds;
|
|
int daysSince1970 = msSince1970 ~/ Duration.millisecondsPerDay;
|
|
// 1970-1-1 was Thursday
|
|
return ((daysSince1970 + DateTime.thursday) % DateTime.daysPerWeek);
|
|
}
|
|
|
|
/** Formats a time in H:MM A format */
|
|
// TODO(jmesserly): should get 12 vs 24 hour clock setting from the locale
|
|
static String toHourMinutesString(Duration duration) {
|
|
assert(duration.inDays == 0);
|
|
int hours = duration.inHours;
|
|
String a;
|
|
if (hours >= 12) {
|
|
a = 'pm';
|
|
if (hours != 12) {
|
|
hours -= 12;
|
|
}
|
|
} else {
|
|
a = 'am';
|
|
if (hours == 0) {
|
|
hours += 12;
|
|
}
|
|
}
|
|
String twoDigits(int n) {
|
|
if (n >= 10) return "${n}";
|
|
return "0${n}";
|
|
}
|
|
|
|
String mm =
|
|
twoDigits(duration.inMinutes.remainder(Duration.minutesPerHour));
|
|
return "${hours}:${mm} ${a}";
|
|
}
|
|
}
|