/// [Time] is used as a way to serialize and deserialize time based notations. /// /// When interacting with this, you can even parse Durations class Time { int days; int hours; int minutes; int seconds; Time( {required this.days, required this.hours, required this.minutes, required this.seconds}) { autofix(); } static Time fromDuration(Duration duration) { int days = duration.inDays; int hours = duration.inHours.remainder(24); int minutes = duration.inMinutes.remainder(60); int seconds = duration.inSeconds.remainder(60); return Time(days: days, hours: hours, minutes: minutes, seconds: seconds); } Duration toDuration() { return Duration( days: days, hours: hours, minutes: minutes, seconds: seconds); } int getTotalSeconds() { int current = 0; current += seconds; current += (minutes * 60); // 60 seconds in a minute current += (hours * 60 * 60); // 60 seconds, 60 minutes in an hour return current; } void add(Time time) { seconds += time.getTotalSeconds(); autofix(); } void subtract(Time time) { int sec = getTotalSeconds(); sec -= time.getTotalSeconds(); apply(sec); } void tickDown() { int sec = getTotalSeconds(); sec--; apply(sec); } void tickUp() { int sec = getTotalSeconds(); sec++; apply(sec); } void apply(int seconds) { hours = 0; minutes = 0; this.seconds = seconds; if (this.seconds < 0) this.seconds = 0; autofix(); } void autofix() { int totalSeconds = getTotalSeconds(); if (totalSeconds < 0) totalSeconds = 0; int one_day = (1 * 60 * 60 * 24); int one_hour = (1 * 60 * 60); int one_minute = (1 * 60); int days = (totalSeconds / 60 / 60 / 24).round(); totalSeconds -= (days * one_day); int hours = (totalSeconds / 60 / 60).round(); totalSeconds -= (hours * one_hour); int minutes = (totalSeconds / 60).round(); totalSeconds -= (minutes * one_minute); int seconds = totalSeconds; this.days = days; this.hours = hours; this.minutes = minutes; this.seconds = seconds; } Time copy() { return Time(days: days, hours: hours, minutes: minutes, seconds: seconds); } factory Time.copy(Time other) { return Time( days: other.days, hours: other.hours, minutes: other.minutes, seconds: other.seconds); } factory Time.fromNotation(String notation) { int days = 0; int hours = 0; int minutes = 0; int seconds = 0; List current = []; String val = notation; if (val.indexOf('d') == -1) { days = 0; } else { current = val.split('d'); days = int.parse(current[0]); if (current.length == 2) { val = current[1]; } else val = ""; } if (val.indexOf('h') == -1) { hours = 0; } else { current = val.split('h'); hours = int.parse(current[0]); if (current.length == 2) val = current[1]; else val = ""; } if (val.indexOf('m') == -1) { minutes = 0; } else { current = val.split('m'); minutes = int.parse(current[0]); if (current.length == 2) val = current[1]; else val = ""; } if (val.indexOf('s') == -1) { seconds = 0; } else { current = val.split('s'); seconds = int.parse(current[0]); if (current.length == 2) val = current[1]; else val = ""; } if (val != "") { seconds += int.parse(val); } return Time(days: days, hours: hours, minutes: minutes, seconds: seconds); } @override String toString() { List parts = []; if (days > 0) parts.add('${days}d'); if (hours > 0) parts.add('${hours}h'); if (minutes > 0) parts.add('${minutes}m'); if (seconds > 0) parts.add('${seconds}s'); return parts.join(' '); } } /// Provides some functionality dart lacks internally. /// /// WARNING: A potential race condition can be met by using the nano time here. /// /// Long run times may eventually reach a maximum possible value. To prevent this, code should make use of the resetNanoTime function. class TimeUtils { /// This locks the internal timer and stops execution bool _tslock = false; int _ns = 0; TimeUtils._(); static TimeUtils? _inst; factory TimeUtils() { _inst ??= TimeUtils._(); return _inst!; } /// Returns a unix timestamp static int getUnixTimestamp() { return (DateTime.now().millisecondsSinceEpoch / 1000).round(); } /// Converts a unix timestamp back into DateTime format. static DateTime parseTimestamp(int unixTimestamp) { return DateTime.fromMillisecondsSinceEpoch(unixTimestamp * 1000); } /// Starts the time tracker. static void initTimeTracker() { TimeUtils tu = TimeUtils(); tu._tslock = false; tu._timeLoop(); } /// Stops the time tracker static void stopTimeTracker() { TimeUtils tu = TimeUtils(); tu._tslock = true; } /// Resets the currently tracked nanoTime. static void resetNanoTime() { TimeUtils tu = TimeUtils(); tu._ns = 0; } /// This is the loop which will keep a facsimile of nanoseconds since start. Future _timeLoop() async { _ns = 0; while (!_tslock) { await Future.delayed( Duration(microseconds: 1)); // Simulate 1 microsecond delay _ns += 1000; // Increment by 1000 nanoseconds (1 microsecond) } } /// Returns the current simulated nanotime. static int getNanoTime() { TimeUtils tu = TimeUtils(); return tu._ns; } }