23

I need to get day of year (day1 is 1rst of january), week of year, and month of year from a dart DateTime object.

I did not find any available library for this. Any idea ?

fvisticot
  • 7,936
  • 14
  • 49
  • 79

12 Answers12

44

[ORIGINAL ANSWER - Please scroll below to the updated answer, which has an updated calculation]

Week of year:

/// Calculates week number from a date as per https://en.wikipedia.org/wiki/ISO_week_date#Calculation
int weekNumber(DateTime date) {
  int dayOfYear = int.parse(DateFormat("D").format(date));
  return ((dayOfYear - date.weekday + 10) / 7).floor();
}

The rest is available through DateFormat (part of the intl package).

[UPDATED ANSWER] As pointed out by Henrik Kirk in a comment, the original answer did not include the necessary correction for certain dates. Here is a full implementation of the ISO week date calculation.

/// Calculates number of weeks for a given year as per https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year
int numOfWeeks(int year) {
  DateTime dec28 = DateTime(year, 12, 28);
  int dayOfDec28 = int.parse(DateFormat("D").format(dec28));
  return ((dayOfDec28 - dec28.weekday + 10) / 7).floor();
}

/// Calculates week number from a date as per https://en.wikipedia.org/wiki/ISO_week_date#Calculation
int weekNumber(DateTime date) {
  int dayOfYear = int.parse(DateFormat("D").format(date));
  int woy =  ((dayOfYear - date.weekday + 10) / 7).floor();
  if (woy < 1) {
    woy = numOfWeeks(date.year - 1);
  } else if (woy > numOfWeeks(date.year)) {
    woy = 1;
  }
  return woy;
}
András Szepesházi
  • 6,483
  • 5
  • 45
  • 59
16

Day of year

final date = someDate;
final diff = now.difference(new DateTime(date.year, 1, 1, 0, 0));
final diffInDays = diff.inDays;

Week of year

final date = someDate;
final startOfYear = new DateTime(date.year, 1, 1, 0, 0);
final firstMonday = startOfYear.weekday;
final daysInFirstWeek = 8 - firstMonday;
final diff = date.difference(startOfYear);
var weeks = ((diff.inDays - daysInFirstWeek) / 7).ceil();
// It might differ how you want to treat the first week
if(daysInFirstWeek > 3) {
  weeks += 1;
}

Month of year

final monthOfYear = new DateTime.now().month;

Caution: That's not battle-tested code.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    If he's considering YYYY-01-01 to be "day 1" then you'll need to add 1 to the difference, otherwise it will be off. – Herohtar Mar 21 '18 at 14:53
  • 3
    Also, since date differences are based on hours, there can be some issues due to DST when working with local time. – Herohtar Mar 21 '18 at 14:59
  • 1
    Local time is a good hint. Thanks @Herohtar. Using `someDate().toUtc()` should avoid such issues. – Günter Zöchbauer Mar 21 '18 at 15:05
  • 2
    I think your week of year function does not correctly for dates like 2019-12-31, which is actually in the first calendar week of 2020 (in ISO 8601). I pasted my implementation below which works in these edge cases – boformer Jul 01 '18 at 10:55
  • 1
    "Day of year" function returns incorrect result! Converting to UTC does not help. – BambinoUA Jun 20 '19 at 14:31
14

Try this really simple dart package, Jiffy. The code below will help

To get date day of year

// This will return the day of year from now
Jiffy.now().dayOfYear; // 295

// You can also pass in a dateTime object
Jiffy.parseFromDateTime(DateTime(2019, 1, 3)).dayOfYear; // 3

To get week of year

Jiffy.now().week; // 43

// You can also pass in an Array or Map
Jiffy.parseFromList([2019, 1, 3]).week; // 1

To get month of year

Jiffy.now().month; // 10

Jiffy.parseFromMap({
    "year": 2019,
    "month": 1,
    "day": 3
  }).month; // 1

Hope this answer helps

Jama Mohamed
  • 3,057
  • 4
  • 29
  • 43
6

This is my implementation of ISO 8601 Week of Year in Dart:

int getWeekOfYear(DateTime date) {
  final weekYearStartDate = getWeekYearStartDateForDate(date);
  final dayDiff = date.difference(weekYearStartDate).inDays;
  return ((dayDiff + 1) / 7).ceil();
}

DateTime getWeekYearStartDateForDate(DateTime date) {
  int weekYear = getWeekYear(date);
  return getWeekYearStartDate(weekYear);
}

int getWeekYear(DateTime date) {
  assert(date.isUtc);

  final weekYearStartDate = getWeekYearStartDate(date.year);

  // in previous week year?
  if(weekYearStartDate.isAfter(date)) {
    return date.year - 1;
  }

  // in next week year?
  final nextWeekYearStartDate = getWeekYearStartDate(date.year + 1);
  if(isBeforeOrEqual(nextWeekYearStartDate, date)) {
    return date.year + 1;
  }

  return date.year;
}

DateTime getWeekYearStartDate(int year) {
  final firstDayOfYear = DateTime.utc(year, 1, 1);
  final dayOfWeek = firstDayOfYear.weekday;
  if(dayOfWeek <= DateTime.thursday) {
    return addDays(firstDayOfYear, 1 - dayOfWeek);
  }
  else {
    return addDays(firstDayOfYear, 8 - dayOfWeek);
  }
}

Note that the "week year" is not always the calendar year, it could also be the one before or after:

void printWeekOfYear(DateTime date) {
  print('week ${getWeekOfYear(date)} in year ${getWeekYear(date)}');
}

printWeekOfYear(DateTime.utc(2017, 1, 1));
// --> week 52 in year 2016

printWeekOfYear(DateTime.utc(2019, 12, 31));
// --> week 1 in year 2020
boformer
  • 28,207
  • 10
  • 81
  • 66
  • Thanks for your answer. It works. I added some piece of code for your missing functions `isBeforeOrEqual()` and `addDays()`. `if(date.isAfter(nextWeekYearStartDate)||Utils.isSameDay(date, nextWeekYearStartDate)){ return date.year + 1; }` and `if(dayOfWeek <= DateTime.thursday) { return firstDayOfYear.subtract(Duration(days: dayOfWeek-1)); } else { return firstDayOfYear.add(Duration(days:8 - dayOfWeek )) }` – mDonmez Jul 11 '19 at 15:01
6

Number Week according to ISO 8601

int isoWeekNumber(DateTime date) {
    int daysToAdd = DateTime.thursday - date.weekday;
    DateTime thursdayDate = daysToAdd > 0 ? date.add(Duration(days: daysToAdd)) : date.subtract(Duration(days: daysToAdd.abs()));
    int dayOfYearThursday = dayOfYear(thursdayDate);
    return 1 + ((dayOfYearThursday - 1) / 7).floor();
}
int dayOfYear(DateTime date) {
    return date.difference(DateTime(date.year, 1, 1)).inDays;
}
5

Dart SDK2.8.4 and later:
day of the year , with no packages:

void main(){
  final now = new DateTime.now();
  final todayInDays = now.difference(new DateTime(now.year,1,1,0,0)).inDays; //return 157
}


reference (official)> inDays, from Dart Official documentation

Arthur Zennig
  • 2,058
  • 26
  • 20
3

I wrote another solution based on your answers, it seem to work fine, but please feel free to give me feedback if you see a problem:

class DateUtils {

  static int currentWeek() {
    return weekOfYear(DateTime.now());
  }

  static int weekOfYear(DateTime date) {
    DateTime monday = weekStart(date);
    DateTime first = weekYearStartDate(monday.year);

    int week = 1 + (monday.difference(first).inDays / 7).floor();

    if (week == 53 && DateTime(monday.year, 12, 31).weekday < 4)
      week = 1;

    return week;
  }

  static DateTime weekStart(DateTime date) {
    // This is ugly, but to avoid problems with daylight saving
    DateTime monday = DateTime.utc(date.year, date.month, date.day);
    monday = monday.subtract(Duration(days: monday.weekday - 1));

    return monday;
  }

  static DateTime weekEnd(DateTime date) {
    // This is ugly, but to avoid problems with daylight saving
    // Set the last microsecond to really be the end of the week
    DateTime sunday = DateTime.utc(date.year, date.month, date.day, 23, 59, 59, 999, 999999);
    sunday = sunday.add(Duration(days: 7 - sunday.weekday));

    return sunday;
  }

  static DateTime weekYearStartDate(int year) {
    final firstDayOfYear = DateTime.utc(year, 1, 1);
    final dayOfWeek = firstDayOfYear.weekday;

    return firstDayOfYear.add(Duration(days: (dayOfWeek <= DateTime.thursday ? 1 : 8) - dayOfWeek));
  }
}
UglyBob
  • 247
  • 1
  • 14
  • I think this should be the accepted answer. It's the only one giving the correct week number for the following dates: 2017-1-1 should be 52; 2017-1-2 should be 1' 2020- 12-28 should be 53 – Robin Dijkhof Dec 27 '19 at 19:07
0
getWeekOfYear(){
    DateTime _kita=DateTime.now();
    int d=DateTime.parse("${_kita.year}-01-01").millisecondsSinceEpoch;
    int t= _kita.millisecondsSinceEpoch;
    double daydiff= (t- d)/(1000 * (3600 * 24));
    double week= daydiff/7;
    return(week.ceil());
}

Tested and working you do not need any package

Kjut
  • 56
  • 4
0

This calculation works for me.

int dayOfWeek({DateTime date}) {
  if (date == null)
    date = DateTime.now();

  int w = ((dayOfYear(date) - date.weekday + 10) / 7).floor();

  if (w == 0) {
    w = getYearsWeekCount(date.year-1);
  } else if (w == 53) {
    DateTime lastDay = DateTime(date.year, DateTime.december, 31);
    if (lastDay.weekday < DateTime.thursday) {
      w = 1;
    }
  }
  return w;
}

int getYearsWeekCount(int year) {
  DateTime lastDay = DateTime(year, DateTime.december, 31);
  int count = dayOfWeek(date: lastDay);
  if (count == 1)
    count = dayOfWeek(date: lastDay.subtract(Duration(days: 7)));
  return count;
}

int dayOfYear(DateTime date) {
  int total = 0;
  for (int i = 1; i < date.month; i++) {
    total += getDayOfMonth(date.year, i);
  }
  total+=date.day;
  return total;
}

int getDayOfMonth(int year, int month) {
  final List<int> days = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  if (year % 4 == 0) days[DateTime.february]++;
  return days[month];
}
Mali
  • 593
  • 6
  • 7
0

the previous most voted solution is not working, if the year changes. for example has December 2020 a 53. week and if i change to January 2021 the previous solution computed 0 and not 53.

so i wrote a DateTime extension to cover year change.

  int get weekNumber {
    if (weekday > DateTime.thursday) {
      int toSubstract = weekday - DateTime.thursday;
      DateTime thursday = subtract(Duration(days: toSubstract));

      if (thursday.year != year) {
        return thursday.weekNumber;
      }
    }

    int dayOfYear = int.parse(format('D'));
    return ((dayOfYear - weekday + 10) / 7).floor();
  }
maerlyn
  • 83
  • 9
0

The correct answer of @András Szepesházi but as DateTime extension

extension DateTimeExt on DateTime {
  /// Calculates week number from a date as per https://en.wikipedia.org/wiki/ISO_week_date#Calculation
  int get weekNumber {
    int dayOfYear = int.parse(DateFormat("D").format(this));
    int woy = ((dayOfYear - weekday + 10) / 7).floor();
    if (woy < 1) {
      woy = _numOfWeeks(year - 1);
    } else if (woy > _numOfWeeks(year)) {
      woy = 1;
    }
    return woy;
  }

  /// Calculates number of weeks for a given year as per https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year
  int _numOfWeeks(int year) {
    DateTime dec28 = DateTime(year, 12, 28);
    int dayOfDec28 = int.parse(DateFormat("D").format(dec28));
    return ((dayOfDec28 - dec28.weekday + 10) / 7).floor();
  }
}
Adam Smaka
  • 5,977
  • 3
  • 50
  • 55
0
  static int getWeekNumber(DateTime datetime) {
    var day1 = DateTime(datetime.year);
    DateTime firstMonday;
    switch (day1.weekday) {
      case 1: // mon
        firstMonday = day1;
        break;
      case 2: // tue
        firstMonday = day1.add(const Duration(days: 6));
        break;
      case 3: // wed
        firstMonday = day1.add(const Duration(days: 5));
        break;
      case 4: // thir
        firstMonday = day1.add(const Duration(days: 4));
        break;
      case 5: // fri
        firstMonday = day1.add(const Duration(days: 3));
        break;
      case 6: // sat
        firstMonday = day1.add(const Duration(days: 2));
        break;
      case 7: // sun
        firstMonday = day1.add(const Duration(days: 1));
        break;
      default:
        firstMonday = day1;
    }

    Duration sinceStartOfYear = datetime.diff(firstMonday);
    double weekNo = (sinceStartOfYear.inDays / 7);
    var no = weekNo.floor();

    return no + 1;
  }

My full tested method.

nđq
  • 388
  • 5
  • 14