Skip to content

Commit 9226606

Browse files
authored
feat: add method subtractRound to prevent date overflow (#42)
1 parent 95282a1 commit 9226606

File tree

4 files changed

+62
-51
lines changed

4 files changed

+62
-51
lines changed

API.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Also inherit from Day.js, part of manipulations is immutable.
2929
- [Add `.add(int val, String unit)`](#add-addint-val-string-unit)
3030
- [Add Round `.addRound(int val, String unit)`](#add-round-addroundint-val-string-unit)
3131
- [Subtract `.subtract(int val, String unit)`](#subtract-subtractint-val-string-unit)
32+
- [Subtract Round `.subtractRound(int val, String unit)`](#subtract-round-subtractroundint-val-string-unit)
3233
- [Inc (Same as add)](#inc-same-as-add)
3334
- [Dec (Same as subtract)](#dec-same-as-subtract)
3435
- [Displaying](#displaying)
@@ -309,12 +310,27 @@ d.addRound(1, 'month'); // 2022-04-30T15:52:50.000Z
309310

310311
Returns a cloned day with a specified amount of time subtracted.
311312

313+
So if you wanna receive a non-overflow date, you should use `.subtractRound()` method below.
314+
315+
Refer to [`.add()`](#add-addint-val-string-unit) for more details.
316+
312317
```dart
313318
final d = Day();
314319
315320
d.subtract(1, 'date');
316321
```
317322

323+
### Subtract Round `.subtractRound(int val, String unit)`
324+
325+
Returns a cloned day with a specified amount of time subtracted but rounded to the last day of the current month if overflowed.
326+
327+
```dart
328+
final d = Day.fromString('2022-03-31T15:52:50.000Z');
329+
330+
d.subtract(1, 'month'); // 2022-03-03T15:52:50.000Z
331+
d.subtractRound(1, 'month'); // 2022-02-28T15:52:50.000Z
332+
```
333+
318334
### Inc (Same as add)
319335

320336
A `.add()` shorthand.

lib/src/day.dart

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ class Day {
331331
Day? _add({
332332
required int val,
333333
required String unit,
334+
bool opposite = false,
334335
bool rounded = false,
335336
}) {
336337
final processedUnit = Unit.fromShorthand(unit);
@@ -339,13 +340,13 @@ class Day {
339340
if (duration != null) {
340341
final d = clone();
341342

342-
d._time = d._time.add(duration);
343+
d._time = !opposite ? d._time.add(duration) : d._time.subtract(duration);
343344
d._parseTime();
344345

345346
return d;
346347
} else {
347348
if (unit == Unit.y || unit == 'y') {
348-
final currentYear = year() + val;
349+
final currentYear = year() + (!opposite ? val : -val);
349350

350351
if (rounded) {
351352
final currentMonth = month();
@@ -364,7 +365,7 @@ class Day {
364365
} else if (unit == Unit.m || unit == 'M') {
365366
final d = clone();
366367

367-
final int result = month() + val;
368+
final int result = month() + (!opposite ? val : -val);
368369

369370
if (result > 0) {
370371
d.setValue(Unit.m, result);
@@ -423,39 +424,11 @@ class Day {
423424
/// subtract(1, 'date');
424425
/// subtract(1, 'd');
425426
/// ```
426-
dynamic subtract(int val, String unit) {
427-
final processedUnit = Unit.fromShorthand(unit);
428-
final duration = u.durationFromUnit(val, processedUnit);
429-
430-
if (duration != null) {
431-
final d = clone();
432-
433-
d._time = d._time.subtract(duration);
434-
d._parseTime();
435-
436-
return d;
437-
} else {
438-
if (unit == Unit.y || unit == 'y') {
439-
return _cloneAndSetSingleValue(Unit.y, year() - val);
440-
} else if (unit == Unit.m || unit == 'M') {
441-
final int result = month() - val;
442-
443-
final d = clone();
444-
if (result > 0) {
445-
d.setValue(Unit.m, result);
446-
} else {
447-
d
448-
..setValue(Unit.y, d.year() - (result.abs() ~/ 12 + 1))
449-
..setValue(Unit.m, 12 - result.abs() % 12);
450-
}
451-
d.finished();
427+
Day? subtract(int val, String unit) =>
428+
_add(val: val, unit: unit, opposite: true);
452429

453-
return d;
454-
}
455-
}
456-
457-
return null;
458-
}
430+
Day? subtractRound(int val, String unit) =>
431+
_add(val: val, unit: unit, opposite: true, rounded: true);
459432

460433
/// Alias of [add].
461434
dynamic inc(int val, String unit) => add(val, unit);

test/day_subtract_round_test.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import 'package:test/test.dart';
2+
import 'package:day/day.dart';
3+
4+
void main() {
5+
test(
6+
'.subtractRound(1, \'M\') returns a date not exceeding the current month',
7+
() {
8+
final d = Day.fromString('2022-03-31T15:52:50.000Z').subtractRound(1, 'M')!;
9+
10+
expect(d.month(), equals(2));
11+
expect(d.date(), 28);
12+
});
13+
14+
test(
15+
'.subtractRound(1, \'y\') returns a date not exceeding the current month',
16+
() {
17+
final d = Day.fromString('2020-02-29T15:52:50.000Z').subtractRound(1, 'y')!;
18+
19+
expect(d.month(), equals(2));
20+
expect(d.date(), 28);
21+
});
22+
}

test/day_subtract_test.dart

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,31 @@ void main() {
66

77
group('Subtract Method:', () {
88
test('1 year', () {
9-
final Day dClone = d.subtract(1, 'year');
9+
final dClone = d.subtract(1, 'year')!;
1010

1111
expect(d.year(), equals(2019));
1212

1313
expect(dClone.year(), equals(2018));
1414
});
1515

1616
test('-1 year', () {
17-
final Day dClone = d.subtract(-1, 'year');
17+
final dClone = d.subtract(-1, 'year')!;
1818

1919
expect(d.year(), equals(2019));
2020

2121
expect(dClone.year(), equals(2020));
2222
});
2323

2424
test('2 months', () {
25-
final Day dClone = d.subtract(2, 'month');
25+
final dClone = d.subtract(2, 'month')!;
2626

2727
expect(d.month(), equals(4));
2828

2929
expect(dClone.month(), equals(3));
3030
});
3131

3232
test('4 months', () {
33-
final Day dClone = d.subtract(4, 'month');
33+
final dClone = d.subtract(4, 'month')!;
3434

3535
expect(d.year(), equals(2019));
3636
expect(d.month(), equals(4));
@@ -40,7 +40,7 @@ void main() {
4040
});
4141

4242
test('28 months', () {
43-
final Day dClone = d.subtract(28, 'month');
43+
final dClone = d.subtract(28, 'month')!;
4444

4545
expect(d.year(), equals(2019));
4646
expect(d.month(), equals(4));
@@ -50,7 +50,7 @@ void main() {
5050
});
5151

5252
test('-8 months', () {
53-
final Day dClone = d.subtract(-8, 'month');
53+
final dClone = d.subtract(-8, 'month')!;
5454

5555
expect(d.year(), equals(2019));
5656
expect(d.month(), equals(4));
@@ -60,7 +60,7 @@ void main() {
6060
});
6161

6262
test('-9 months', () {
63-
final Day dClone = d.subtract(-9, 'month');
63+
final dClone = d.subtract(-9, 'month')!;
6464

6565
expect(d.year(), equals(2019));
6666
expect(d.month(), equals(4));
@@ -70,7 +70,7 @@ void main() {
7070
});
7171

7272
test('1 day', () {
73-
final Day dClone = d.subtract(1, 'date');
73+
final dClone = d.subtract(1, 'date')!;
7474

7575
expect(d.month(), equals(4));
7676
expect(d.date(), equals(30));
@@ -80,63 +80,63 @@ void main() {
8080
});
8181

8282
test('1 hour', () {
83-
final Day dClone = d.subtract(1, 'hour');
83+
final dClone = d.subtract(1, 'hour')!;
8484

8585
expect(d.hour(), equals(10));
8686

8787
expect(dClone.hour(), equals(9));
8888
});
8989

9090
test('-1 hour', () {
91-
final Day dClone = d.subtract(-1, 'hour');
91+
final dClone = d.subtract(-1, 'hour')!;
9292

9393
expect(d.hour(), equals(10));
9494

9595
expect(dClone.hour(), equals(11));
9696
});
9797

9898
test('1 minute', () {
99-
final Day dClone = d.subtract(1, 'minute');
99+
final dClone = d.subtract(1, 'minute')!;
100100

101101
expect(d.minute(), equals(30));
102102

103103
expect(dClone.minute(), equals(29));
104104
});
105105

106106
test('-1 minute', () {
107-
final Day dClone = d.subtract(-1, 'minute');
107+
final dClone = d.subtract(-1, 'minute')!;
108108

109109
expect(d.minute(), equals(30));
110110

111111
expect(dClone.minute(), equals(31));
112112
});
113113

114114
test('1 second', () {
115-
final Day dClone = d.subtract(1, 'second');
115+
final dClone = d.subtract(1, 'second')!;
116116

117117
expect(d.second(), equals(30));
118118

119119
expect(dClone.second(), equals(29));
120120
});
121121

122122
test('-1 second', () {
123-
final Day dClone = d.subtract(-1, 'second');
123+
final dClone = d.subtract(-1, 'second')!;
124124

125125
expect(d.second(), equals(30));
126126

127127
expect(dClone.second(), equals(31));
128128
});
129129

130130
test('1 ms', () {
131-
final Day dClone = d.subtract(1, 'ms');
131+
final dClone = d.subtract(1, 'ms')!;
132132

133133
expect(d.millisecond(), equals(0));
134134

135135
expect(dClone.millisecond(), equals(999));
136136
});
137137

138138
test('-1 ms', () {
139-
final Day dClone = d.subtract(-1, 'ms');
139+
final dClone = d.subtract(-1, 'ms')!;
140140

141141
expect(d.millisecond(), equals(0));
142142

0 commit comments

Comments
 (0)