Skip to content

Instantly share code, notes, and snippets.

@Vonarian
Last active November 26, 2025 06:19
Show Gist options
  • Select an option

  • Save Vonarian/d769bb38afc5d1368cfe6e8b6eaba27e to your computer and use it in GitHub Desktop.

Select an option

Save Vonarian/d769bb38afc5d1368cfe6e8b6eaba27e to your computer and use it in GitHub Desktop.
Time calculation
import 'dart:core';
// Define the start and end times for the main work period
// These can now be "h:mm AM/PM" or "HH:mm"
// Example for 24-hour format:
// String startTimeStr = "08:46";
// String endTimeStr = "17:30";
// Example for mixed formats:
// String startTimeStr = "8:46 AM";
// String endTimeStr = "17:30";
String startTimeStr = "08:24 AM";
String endTimeStr = "5:33 PM";
// Define a list of leave periods
final List<LeaveTime> leavePeriods = [
LeaveTime(start: "12:00 PM", end: "1:00 PM"), // Lunch
LeaveTime(start: "3:00 PM", end: "3:15 PM"), // Short break
// Example of an unparsable leave time to test error handling
// LeaveTime(start: "invalid", end: "1:00 PM"),
// Example of an invalid leave period (end before start)
// LeaveTime(start: "3:00 PM", end: "2:00 PM"),
];
/// Parses a time string, supporting both "h:mm AM/PM" (12-hour)
/// and "HH:mm" (24-hour) formats.
///
/// Returns a [DateTime] object with a fixed arbitrary date (Jan 1, 2025)
/// and the parsed time, or `null` if the string cannot be parsed.
DateTime? parseTime(String timeStr) {
try {
final timeStrUpper = timeStr.toUpperCase();
final is12HourFormat =
timeStrUpper.contains("AM") || timeStrUpper.contains("PM");
int hour;
int minute;
if (is12HourFormat) {
final parts = timeStr.split(" ");
if (parts.length != 2) return null; // Expected "time meridian"
final hmParts = parts[0].split(":");
if (hmParts.length != 2) return null; // Expected "h:mm"
hour = int.parse(hmParts[0]);
minute = int.parse(hmParts[1]);
String meridian = parts[1].toUpperCase();
if (meridian == "PM" && hour != 12) {
hour += 12;
} else if (meridian == "AM" && hour == 12) {
hour = 0; // 12 AM (midnight) is 00:xx in 24-hour format
}
// Basic validation for parsed hour/minute values
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
return null;
}
} else {
// Assume 24-hour format (HH:mm)
final hmParts = timeStr.split(":");
if (hmParts.length != 2) return null; // Expected "HH:mm"
hour = int.parse(hmParts[0]);
minute = int.parse(hmParts[1]);
// Basic validation for parsed hour/minute values
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
return null;
}
}
// Use a fixed date; only the time component is relevant for duration.
return DateTime(2025, 1, 1, hour, minute);
} on FormatException {
// Catch errors from int.parse if the number format is invalid
return null;
} catch (e) {
// Catch any other unexpected errors during parsing
return null;
}
}
/// Represents a period of leave time with a start and end time string.
class LeaveTime {
final String start;
final String end;
LeaveTime({required this.start, required this.end});
/// Calculates the duration of this leave period.
/// Returns a [Duration] object, or `null` if parsing fails for start or end time,
/// or if the end time is before the start time.
Duration? getDuration() {
final DateTime? startTime = parseTime(start);
final DateTime? endTime = parseTime(end);
if (startTime == null) {
print(
"Warning: Could not parse leave start time '$start'. Skipping this leave period.",
);
return null;
}
if (endTime == null) {
print(
"Warning: Could not parse leave end time '$end'. Skipping this leave period.",
);
return null;
}
// A leave duration should always be positive. If end is before start, it's invalid.
if (endTime.isBefore(startTime)) {
print(
"Warning: Leave end time '$end' is before start time '$start'. Skipping this leave period.",
);
return null;
}
return endTime.difference(startTime);
}
}
void main() {
DateTime? startTime = parseTime(startTimeStr);
DateTime? endTime = parseTime(endTimeStr);
if (startTime == null) {
print(
"Error: Could not parse main work start time '$startTimeStr'. Please use 'h:mm AM/PM' or 'HH:mm' format.",
);
return;
}
if (endTime == null) {
print(
"Error: Could not parse main work end time '$endTimeStr'. Please use 'h:mm AM/PM' or 'HH:mm' format.",
);
return;
}
// Calculate total scheduled work duration
Duration scheduledWorkDuration = endTime.difference(startTime);
// If the end time is before the start time for the main work, it's an error in this context.
if (scheduledWorkDuration.isNegative) {
print(
"Error: Main work end time '$endTimeStr' is before start time '$startTimeStr'. "
"Please ensure end time is after start time on the same day.",
);
return;
}
// Calculate total leave duration from the list of leave periods
Duration totalLeaveDuration = Duration.zero;
for (final leave in leavePeriods) {
final Duration? leaveDuration = leave.getDuration();
if (leaveDuration != null) {
totalLeaveDuration += leaveDuration;
}
}
// Calculate net work duration by subtracting total leave from scheduled work
Duration netWorkDuration = scheduledWorkDuration - totalLeaveDuration;
// Ensure net work duration is not negative (e.g., if leave times exceed scheduled work time)
if (netWorkDuration.isNegative) {
netWorkDuration = Duration.zero;
}
// --- Display scheduled work details ---
final int totalMinutesScheduled = scheduledWorkDuration.inMinutes;
final int totalHoursScheduled =
totalMinutesScheduled ~/ 60; // Integer division
final int minuteAfterHoursScheduled = totalMinutesScheduled % 60; // Remainder
print(
"Scheduled work time from $startTimeStr to $endTimeStr is "
"$totalMinutesScheduled minutes / ${totalHoursScheduled}h ${minuteAfterHoursScheduled}m.",
);
// --- Display leave details (if any) ---
if (totalLeaveDuration.inMinutes > 0) {
final int totalMinutesLeave = totalLeaveDuration.inMinutes;
final int totalHoursLeave = totalMinutesLeave ~/ 60;
final int minuteAfterHoursLeave = totalMinutesLeave % 60;
print(
"Total leave time applied: $totalMinutesLeave minutes / ${totalHoursLeave}h ${minuteAfterHoursLeave}m.",
);
} else {
print("No leave periods were applied.");
}
// --- Display net work details ---
final int netTotalMinutes = netWorkDuration.inMinutes;
final int netTotalHours = netTotalMinutes ~/ 60;
final int netMinuteAfterHours = netTotalMinutes % 60;
print(
"Net work time after leave is $netTotalMinutes minutes / ${netTotalHours}h ${netMinuteAfterHours}m.",
);
// --- Check against minimum work requirement ---
const int requiredWorkMinutes = 480; // 8 hours * 60 minutes/hour
if (netTotalMinutes < requiredWorkMinutes) {
print(
'\n!!!!!!Net work time (${netTotalMinutes}m) does not meet the minimum work requirement of ${requiredWorkMinutes} minutes!!!!!!',
);
print('You are short by ${requiredWorkMinutes - netTotalMinutes} minutes.');
} else {
print(
'\nCongratulations! You met the minimum work time. '
'You have ${netTotalMinutes - requiredWorkMinutes} minutes extra.',
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment