relative method
Constructs a new DateTime instance based on modifier
.
The modifier
string must not be null
. Returns null
if the
modifier
string cannot be parsed.
This function parses the modifier
string using this format:
[+|-|blank]<integer><unit>@[+|-|blank]<unit>
When the sign
character is missing, '+' is assumed.
For the instance date and time, use now
.
Examples:
- '-1d' => subtract one day
- '+1w' => add one week
- '-6m' => subtract six months
- '2y' => add two years
- 'now' => current time in this instance
Code examples:
DateTime.now().relative('-1d')
=> yesterdayDateTime.now().relative('@w')
=> SundayDateTime.now().relative('-1y@y')
=> Last New Year's EveDateTime.now().relative('@-y')
=> Last New Year's DayDateTime(2020, 4, 2, 12).relative('-1d')
=> noon on April fool's dayDateTime(2001, 9, 16).relative("-5d")
=> 9/11
The @
character indicates that the instance should adjust (snap)
to the start (-) or end (+) of the unit.
Examples:
- '@-d' => start of the day
- '@+w' => end of the week
- '@m' => end of the month
- '@-y => start of the year
Code examples:
DateTime.now().relative('@-y')
=> start of this yearDateTime.now().relative('+y')
=> end of this yearDateTime.now().relative('-1y@-y')
=> start of last yearDateTime.now().relative('-1y@+y')
=> end of last year
BNF:
- modifier ::= time_modifier snap_to
- time_modifier ::=
- unit ::= 'd' | 'w' | 'm' | 'y'
- time_integer ::= digit{*}
- sign ::=
- sign_opt ::=
- snap_to ::=
- snap ::= '@' unit snap_modifier
- snap_modifier ::=
Snap moves to start or end of time unit after applying time modifier. You specify the start of a time unit with '-' character, and end of the time unit with the '+' character, and no character defaults to end. Snap examples:
-
Start of current month: @-m
-
End of current month: @+m or @m
-
Start of previous month: -1m@-m
-
End of previous month: -1m@+m or -1m@m
-
Start of current year: @-y
-
End of current year: @+y or @y
-
Start of previous year: -1y@-y
-
End of previous year: -1y@+y or -1y@y
Implementation
/// Snap examples:
/// * Start of current month: @-m
/// * End of current month: @+m or @m
/// * Start of previous month: -1m@-m
/// * End of previous month: -1m@+m or -1m@m
///
/// * Start of current year: @-y
/// * End of current year: @+y or @y
/// * Start of previous year: -1y@-y
/// * End of previous year: -1y@+y or -1y@y
DateTime? relative(String? modifier) {
final parser = DateTimeRelativeParser();
final parsed = parser.relativeParse(modifier);
if (parsed.error) {
return null;
}
if (parsed.now) {
return this;
}
final jif =
Jiffy.unixFromMillisecondsSinceEpoch(this!.millisecondsSinceEpoch);
if (parsed.timeUnitMatch == 'd') {
parsed.neg!
? jif.subtract(days: parsed.timeInt!)
: jif.add(days: parsed.timeInt!);
} else if (parsed.timeUnitMatch == 'w') {
parsed.neg!
? jif.subtract(weeks: parsed.timeInt!)
: jif.add(weeks: parsed.timeInt!);
} else if (parsed.timeUnitMatch == 'm') {
parsed.neg!
? jif.subtract(months: parsed.timeInt!)
: jif.add(months: parsed.timeInt!);
} else if (parsed.timeUnitMatch == 'y') {
parsed.neg!
? jif.subtract(years: parsed.timeInt!)
: jif.add(years: parsed.timeInt!);
}
if (parsed.snapTimeUnitMatch != null) {
if (parsed.snapTimeUnitMatch == 'd') {
parsed.snapNeg ? jif.startOf(Units.DAY) : jif.endOf(Units.DAY);
} else if (parsed.snapTimeUnitMatch == 'w') {
parsed.snapNeg ? jif.startOf(Units.WEEK) : jif.endOf(Units.WEEK);
} else if (parsed.snapTimeUnitMatch == 'm') {
parsed.snapNeg ? jif.startOf(Units.MONTH) : jif.endOf(Units.MONTH);
} else if (parsed.snapTimeUnitMatch == 'y') {
parsed.snapNeg ? jif.startOf(Units.YEAR) : jif.endOf(Units.YEAR);
}
}
return jif.dateTime;
}