content: import 'package:intl/intl.dart';
  
  class Utils {
    static final DateFormat _monthFormat = DateFormat('MMMM yyyy');
    static final DateFormat _dayFormat = DateFormat('dd');
    static final DateFormat _firstDayFormat = DateFormat('MMM dd');
    static final DateFormat _fullDayFormat = DateFormat('EEE MMM dd, yyyy');
    static final DateFormat _apiDayFormat = DateFormat('yyyy-MM-dd');
  
    static String formatMonth(DateTime d) => _monthFormat.format(d);
  
    static String formatDay(DateTime d) => _dayFormat.format(d);
  
    static String formatFirstDay(DateTime d) => _firstDayFormat.format(d);
  
    static String fullDayFormat(DateTime d) => _fullDayFormat.format(d);
  
    static String apiDayFormat(DateTime d) => _apiDayFormat.format(d);
  
    static const List<String> weekdays = [
      'Sun',
      'Mon',
      'Tue',
      'Wed',
      'Thu',
      'Fri',
      'Sat'
    ];
  
    /// The list of days in a given month
    static List<DateTime> daysInMonth(DateTime month) {
      var first = firstDayOfMonth(month);
      var daysBefore = first.weekday;
      var firstToDisplay = first.subtract(Duration(days: daysBefore));
      var last = Utils.lastDayOfMonth(month);
  
      var daysAfter = 7 - last.weekday;
  
      // If the last day is sunday (7) the entire week must be rendered
      if (daysAfter == 0) {
        daysAfter = 7;
      }
  
      var lastToDisplay = last.add(Duration(days: daysAfter));
      return daysInRange(firstToDisplay, lastToDisplay).toList();
    }
  
    static bool isFirstDayOfMonth(DateTime day) {
      return isSameDay(firstDayOfMonth(day), day);
    }
  
    static bool isLastDayOfMonth(DateTime day) {
      return isSameDay(lastDayOfMonth(day), day);
    }
  
    static DateTime firstDayOfMonth(DateTime month) {
      return DateTime(month.year, month.month);
    }
  
    static DateTime firstDayOfWeek(DateTime day) {
      /// Handle Daylight Savings by setting hour to 12:00 Noon
      /// rather than the default of Midnight
      day = DateTime.utc(day.year, day.month, day.day, 12);
  
      /// Weekday is on a 1-7 scale Monday - Sunday,
      /// This Calendar works from Sunday - Monday
      var decreaseNum = day.weekday % 7;
      return day.subtract(Duration(days: decreaseNum));
    }
  
    static DateTime lastDayOfWeek(DateTime day) {
      /// Handle Daylight Savings by setting hour to 12:00 Noon
      /// rather than the default of Midnight
      day = DateTime.utc(day.year, day.month, day.day, 12);
  
      /// Weekday is on a 1-7 scale Monday - Sunday,
      /// This Calendar's Week starts on Sunday
      var increaseNum = day.weekday % 7;
      return day.add(Duration(days: 7 - increaseNum));
    }
  
    /// The last day of a given month
    static DateTime lastDayOfMonth(DateTime month) {
      var beginningNextMonth = (month.month < 12)
          ? DateTime(month.year, month.month + 1, 1)
          : DateTime(month.year + 1, 1, 1);
      return beginningNextMonth.subtract(Duration(days: 1));
    }
  
    /// Returns a [DateTime] for each day the given range.
    ///
    /// [start] inclusive
    /// [end] exclusive
    static Iterable<DateTime> daysInRange(DateTime start, DateTime end) sync* {
      var i = start;
      var offset = start.timeZoneOffset;
      while (i.isBefore(end)) {
        yield i;
        i = i.add(Duration(days: 1));
        var timeZoneDiff = i.timeZoneOffset - offset;
        if (timeZoneDiff.inSeconds != 0) {
          offset = i.timeZoneOffset;
          i = i.subtract(Duration(seconds: timeZoneDiff.inSeconds));
        }
      }
    }
  
    /// Whether or not two times are on the same day.
    static bool isSameDay(DateTime a, DateTime b) {
      return a.year == b.year && a.month == b.month && a.day == b.day;
    }
  
    static bool isSameWeek(DateTime a, DateTime b) {
      /// Handle Daylight Savings by setting hour to 12:00 Noon
      /// rather than the default of Midnight
      a = DateTime.utc(a.year, a.month, a.day);
      b = DateTime.utc(b.year, b.month, b.day);
  
      var diff = a.toUtc().difference(b.toUtc()).inDays;
      if (diff.abs() >= 7) {
        return false;
      }
  
      var min = a.isBefore(b) ? a : b;
      var max = a.isBefore(b) ? b : a;
      var result = max.weekday % 7 - min.weekday % 7 >= 0;
      return result;
    }
  
    static DateTime previousMonth(DateTime m) {
      int year = m.year;
      int month = m.month;
      int day = m.day;
  
      // Decrease the month
      month--;
  
      // If month goes below January, switch to December of the previous year
      if (month < 1) {
        month = 12;
        year--;
      }
  
      // Handle cases where the day might not exist in the previous month (e.g., March 31st)
      while (day > DateTime(year, month + 1, 0).day) {
        day--;
      }
  
      return DateTime(year, month, day);
    }
  
    static DateTime nextMonth(DateTime m) {
      int year = m.year;
      int month = m.month;
      int day = m.day;
  
      // Increase the month
      month++;
  
      // If month goes beyond December, switch to January of the next year
      if (month > 12) {
        month = 1;
        year++;
      }
  
      // Handle cases where the day might not exist in the next month (e.g., January 31st)
      while (day > DateTime(year, month + 1, 0).day) {
        day--;
      }
  
      return DateTime(year, month, day);
    }
  
    static DateTime previousWeek(DateTime w) {
      return w.subtract(Duration(days: 7));
    }
  
    static DateTime nextWeek(DateTime w) {
      return w.add(Duration(days: 7));
    }
  }
  