Last active
March 22, 2023 21:52
-
-
Save Maistho/e38da422ad5c097c635ccf708ec68251 to your computer and use it in GitHub Desktop.
Calculate the iso week of year in dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension DateWeekExtensions on DateTime { | |
int get isoWeekOfYear { | |
// Get the monday of week 1 | |
final DateTime mondayWeek1 = _isoWeek1Monday(); | |
// If this date is before the first week of the year, it is the same week as the last week of the previous year. | |
if (isBefore(mondayWeek1)) { | |
return DateTime(year - 1, 12, 31).isoWeekOfYear; | |
} | |
final int ordinalWeek1Monday = mondayWeek1.ordinalDate(); | |
final int ordinal = ordinalDate(); | |
// Calculate number of days after monday week 1 | |
int diffInDays = ordinal - ordinalWeek1Monday; | |
// If the monday occurs on the previous year, we'll need to add a year to the diff | |
if (year > mondayWeek1.year) { | |
diffInDays += 365; | |
// If it's a leap year and the leap day is before the date checked, add an extra day | |
if (isLeapYear && DateTime(year, 2, 29).isBefore(this)) { | |
diffInDays += 1; | |
} | |
} | |
// Divide the difference by 7 to get the number of weeks | |
int week = (diffInDays ~/ 7) + 1; | |
// The week wraps around to 1 if week 53 doesn't contain a thursday. | |
// TODO: write more tests for this. Does this work with other dates than dec 31st? | |
if (week == 53 && weekday < DateTime.thursday) { | |
return 1; | |
} | |
return week; | |
} | |
/** | |
* Calculates the ordinal date | |
* The ordinal date is the number of days since December 31st the previous year. | |
* January 1st has the ordinal date 1 | |
* December 31st has the ordinal date 365, or 366 in leap years | |
*/ | |
int ordinalDate() { | |
final DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; | |
final monthsBefore = DAYS_IN_MONTH.getRange(0, month - 1); | |
int days = monthsBefore.length > 0 | |
? monthsBefore.reduce((value, element) => value + element) | |
: 0; | |
if (month > 2 && isLeapYear) { | |
days += 1; | |
} | |
return days + day; | |
} | |
/** | |
* Check if this date is on a leap year | |
*/ | |
bool get isLeapYear { | |
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); | |
} | |
/** | |
* Gets the date of the monday of ISO week 1 this year | |
*/ | |
DateTime _isoWeek1Monday() { | |
final jan4 = DateTime(year, 1, 4); // Jan 4 is always in week 1 | |
return DateTime( | |
jan4.year, | |
jan4.month, | |
jan4.day - jan4.weekday + 1, | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:test/test.dart'; | |
import './datetime_iso_week_of_year.dart'; | |
void t(int year, List<int> expectations) { | |
group("$year", () { | |
test("January 1st", () { | |
expect(DateTime(year, 1, 1).isoWeekOfYear, expectations[0]); | |
}); | |
test("Last of February", () { | |
expect( | |
DateTime(year, 2, DateTime(year).isLeapYear ? 29 : 28).isoWeekOfYear, | |
expectations[1], | |
); | |
}); | |
test("December 31st", () { | |
expect(DateTime(year, 12, 31).isoWeekOfYear, expectations[2]); | |
}); | |
}); | |
} | |
void main() { | |
group("week_of_year", () { | |
t(2000, [52, 9, 52]); | |
t(2001, [1, 9, 1]); | |
t(2002, [1, 9, 1]); | |
t(2003, [1, 9, 1]); | |
t(2004, [1, 9, 53]); | |
t(2005, [53, 9, 52]); | |
t(2006, [52, 9, 52]); | |
t(2007, [1, 9, 1]); | |
t(2008, [1, 9, 1]); | |
t(2009, [1, 9, 53]); | |
t(2010, [53, 8, 52]); | |
t(2011, [52, 9, 52]); | |
t(2012, [52, 9, 1]); | |
t(2013, [1, 9, 1]); | |
t(2014, [1, 9, 1]); | |
t(2015, [1, 9, 53]); | |
t(2016, [53, 9, 52]); | |
t(2017, [52, 9, 52]); | |
t(2018, [1, 9, 1]); | |
t(2019, [1, 9, 1]); | |
t(2020, [1, 9, 53]); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment