1
- import { MILLISECONDS_A_DAY , MILLISECONDS_A_HOUR , MILLISECONDS_A_MINUTE , MILLISECONDS_A_SECOND , MILLISECONDS_A_WEEK , REGEX_FORMAT } from '../../constant'
1
+ import {
2
+ MILLISECONDS_A_DAY ,
3
+ MILLISECONDS_A_HOUR ,
4
+ MILLISECONDS_A_MINUTE ,
5
+ MILLISECONDS_A_SECOND ,
6
+ MILLISECONDS_A_WEEK ,
7
+ REGEX_FORMAT
8
+ } from '../../constant'
2
9
3
10
const MILLISECONDS_A_YEAR = MILLISECONDS_A_DAY * 365
4
11
const MILLISECONDS_A_MONTH = MILLISECONDS_A_DAY * 30
@@ -16,7 +23,7 @@ const unitToMS = {
16
23
weeks : MILLISECONDS_A_WEEK
17
24
}
18
25
19
- const isDuration = d => ( d instanceof Duration ) // eslint-disable-line no-use-before-define
26
+ const isDuration = d => d instanceof Duration // eslint-disable-line no-use-before-define
20
27
21
28
let $d
22
29
let $u
@@ -25,6 +32,30 @@ const wrapper = (input, instance, unit) =>
25
32
new Duration ( input , unit , instance . $l ) // eslint-disable-line no-use-before-define
26
33
27
34
const prettyUnit = unit => `${ $u . p ( unit ) } s`
35
+ const isNegative = number => number < 0
36
+ const roundNumber = number =>
37
+ ( isNegative ( number ) ? Math . ceil ( number ) : Math . floor ( number ) )
38
+ const absolute = number => Math . abs ( number )
39
+ const getNumberUnitFormat = ( number , unit ) => {
40
+ if ( ! number ) {
41
+ return {
42
+ negative : false ,
43
+ format : ''
44
+ }
45
+ }
46
+
47
+ if ( isNegative ( number ) ) {
48
+ return {
49
+ negative : true ,
50
+ format : `${ absolute ( number ) } ${ unit } `
51
+ }
52
+ }
53
+
54
+ return {
55
+ negative : false ,
56
+ format : `${ number } ${ unit } `
57
+ }
58
+ }
28
59
29
60
class Duration {
30
61
constructor ( input , unit , locale ) {
@@ -49,8 +80,14 @@ class Duration {
49
80
const d = input . match ( durationRegex )
50
81
if ( d ) {
51
82
[ , ,
52
- this . $d . years , this . $d . months , this . $d . weeks ,
53
- this . $d . days , this . $d . hours , this . $d . minutes , this . $d . seconds ] = d
83
+ this . $d . years ,
84
+ this . $d . months ,
85
+ this . $d . weeks ,
86
+ this . $d . days ,
87
+ this . $d . hours ,
88
+ this . $d . minutes ,
89
+ this . $d . seconds
90
+ ] = d
54
91
this . calMilliseconds ( )
55
92
return this
56
93
}
@@ -66,39 +103,54 @@ class Duration {
66
103
67
104
parseFromMilliseconds ( ) {
68
105
let { $ms } = this
69
- this . $d . years = Math . floor ( $ms / MILLISECONDS_A_YEAR )
106
+ this . $d . years = roundNumber ( $ms / MILLISECONDS_A_YEAR )
70
107
$ms %= MILLISECONDS_A_YEAR
71
- this . $d . months = Math . floor ( $ms / MILLISECONDS_A_MONTH )
108
+ this . $d . months = roundNumber ( $ms / MILLISECONDS_A_MONTH )
72
109
$ms %= MILLISECONDS_A_MONTH
73
- this . $d . days = Math . floor ( $ms / MILLISECONDS_A_DAY )
110
+ this . $d . days = roundNumber ( $ms / MILLISECONDS_A_DAY )
74
111
$ms %= MILLISECONDS_A_DAY
75
- this . $d . hours = Math . floor ( $ms / MILLISECONDS_A_HOUR )
112
+ this . $d . hours = roundNumber ( $ms / MILLISECONDS_A_HOUR )
76
113
$ms %= MILLISECONDS_A_HOUR
77
- this . $d . minutes = Math . floor ( $ms / MILLISECONDS_A_MINUTE )
114
+ this . $d . minutes = roundNumber ( $ms / MILLISECONDS_A_MINUTE )
78
115
$ms %= MILLISECONDS_A_MINUTE
79
- this . $d . seconds = Math . floor ( $ms / MILLISECONDS_A_SECOND )
116
+ this . $d . seconds = roundNumber ( $ms / MILLISECONDS_A_SECOND )
80
117
$ms %= MILLISECONDS_A_SECOND
81
118
this . $d . milliseconds = $ms
82
119
}
83
120
84
121
toISOString ( ) {
85
- const Y = this . $d . years ? `${ this . $d . years } Y` : ''
86
- const M = this . $d . months ? `${ this . $d . months } M` : ''
122
+ const Y = getNumberUnitFormat ( this . $d . years , 'Y' )
123
+ const M = getNumberUnitFormat ( this . $d . months , 'M' )
124
+
87
125
let days = + this . $d . days || 0
88
126
if ( this . $d . weeks ) {
89
127
days += this . $d . weeks * 7
90
128
}
91
- const D = days ? `${ days } D` : ''
92
- const H = this . $d . hours ? `${ this . $d . hours } H` : ''
93
- const m = this . $d . minutes ? `${ this . $d . minutes } M` : ''
129
+
130
+ const D = getNumberUnitFormat ( days , 'D' )
131
+ const H = getNumberUnitFormat ( this . $d . hours , 'H' )
132
+ const m = getNumberUnitFormat ( this . $d . minutes , 'M' )
133
+
94
134
let seconds = this . $d . seconds || 0
95
135
if ( this . $d . milliseconds ) {
96
136
seconds += this . $d . milliseconds / 1000
97
137
}
98
- const S = seconds ? `${ seconds } S` : ''
99
- const T = ( H || m || S ) ? 'T' : ''
100
- const result = `P${ Y } ${ M } ${ D } ${ T } ${ H } ${ m } ${ S } `
101
- return result === 'P' ? 'P0D' : result
138
+
139
+ const S = getNumberUnitFormat ( seconds , 'S' )
140
+
141
+ const negativeMode =
142
+ Y . negative ||
143
+ M . negative ||
144
+ D . negative ||
145
+ H . negative ||
146
+ m . negative ||
147
+ S . negative
148
+
149
+ const T = H . format || m . format || S . format ? 'T' : ''
150
+ const P = negativeMode ? '-' : ''
151
+
152
+ const result = `${ P } P${ Y . format } ${ M . format } ${ D . format } ${ T } ${ H . format } ${ m . format } ${ S . format } `
153
+ return result === 'P' || result === '-P' ? 'P0D' : result
102
154
}
103
155
104
156
toJSON ( ) {
@@ -136,11 +188,11 @@ class Duration {
136
188
if ( pUnit === 'milliseconds' ) {
137
189
base %= 1000
138
190
} else if ( pUnit === 'weeks' ) {
139
- base = Math . floor ( base / unitToMS [ pUnit ] )
191
+ base = roundNumber ( base / unitToMS [ pUnit ] )
140
192
} else {
141
193
base = this . $d [ pUnit ]
142
194
}
143
- return base
195
+ return base === 0 ? 0 : base // a === 0 will be true on both 0 and -0
144
196
}
145
197
146
198
add ( input , unit , isSubtract ) {
@@ -152,6 +204,7 @@ class Duration {
152
204
} else {
153
205
another = wrapper ( input , this ) . $ms
154
206
}
207
+
155
208
return wrapper ( this . $ms + ( another * ( isSubtract ? - 1 : 1 ) ) , this )
156
209
}
157
210
@@ -170,7 +223,10 @@ class Duration {
170
223
}
171
224
172
225
humanize ( withSuffix ) {
173
- return $d ( ) . add ( this . $ms , 'ms' ) . locale ( this . $l ) . fromNow ( ! withSuffix )
226
+ return $d ( )
227
+ . add ( this . $ms , 'ms' )
228
+ . locale ( this . $l )
229
+ . fromNow ( ! withSuffix )
174
230
}
175
231
176
232
milliseconds ( ) { return this . get ( 'milliseconds' ) }
@@ -190,6 +246,7 @@ class Duration {
190
246
years ( ) { return this . get ( 'years' ) }
191
247
asYears ( ) { return this . as ( 'years' ) }
192
248
}
249
+
193
250
export default ( option , Dayjs , dayjs ) => {
194
251
$d = dayjs
195
252
$u = dayjs ( ) . $utils ( )
0 commit comments