@@ -119,94 +119,74 @@ export function elapsedTime(date: Date, precision: Unit = 'second', now = Date.n
119
119
)
120
120
}
121
121
122
+ const durationRoundingThresholds = [
123
+ Infinity , // Year
124
+ 11 , // Month
125
+ 28 , // Day
126
+ 21 , // Hour
127
+ 55 , // Minute
128
+ 55 , // Second
129
+ 900 , // Millisecond
130
+ ]
131
+
122
132
interface RoundingOpts {
123
133
relativeTo : Date | number
124
134
}
125
135
126
136
export function roundToSingleUnit ( duration : Duration , { relativeTo = Date . now ( ) } : Partial < RoundingOpts > = { } ) : Duration {
127
- relativeTo = new Date ( relativeTo )
128
137
if ( duration . blank ) return duration
129
- const sign = duration . sign
130
- let years = Math . abs ( duration . years )
131
- let months = Math . abs ( duration . months )
132
- let weeks = Math . abs ( duration . weeks )
133
- let days = Math . abs ( duration . days )
134
- let hours = Math . abs ( duration . hours )
135
- let minutes = Math . abs ( duration . minutes )
136
- let seconds = Math . abs ( duration . seconds )
137
- let milliseconds = Math . abs ( duration . milliseconds )
138
-
139
- if ( milliseconds >= 900 ) seconds += Math . round ( milliseconds / 1000 )
140
- if ( seconds || minutes || hours || days || weeks || months || years ) {
141
- milliseconds = 0
142
- }
143
-
144
- if ( seconds >= 55 ) minutes += Math . round ( seconds / 60 )
145
- if ( minutes || hours || days || weeks || months || years ) seconds = 0
146
-
147
- if ( minutes >= 55 ) hours += Math . round ( minutes / 60 )
148
- if ( hours || days || weeks || months || years ) minutes = 0
149
-
150
- if ( days && hours >= 12 ) days += Math . round ( hours / 24 )
151
- if ( ! days && hours >= 21 ) days += Math . round ( hours / 24 )
152
- if ( days || weeks || months || years ) hours = 0
153
-
154
- // Resolve calendar dates
155
- const currentYear = relativeTo . getFullYear ( )
156
- const currentMonth = relativeTo . getMonth ( )
157
- const currentDate = relativeTo . getDate ( )
158
- if ( days >= 27 || years + months + days ) {
159
- const newMonthDate = new Date ( relativeTo )
160
- newMonthDate . setDate ( 1 )
161
- newMonthDate . setMonth ( currentMonth + months * sign + 1 )
162
- newMonthDate . setDate ( 0 )
163
- const monthDateCorrection = Math . max ( 0 , currentDate - newMonthDate . getDate ( ) )
164
-
165
- const newDate = new Date ( relativeTo )
166
- newDate . setFullYear ( currentYear + years * sign )
167
- newDate . setDate ( currentDate - monthDateCorrection )
168
- newDate . setMonth ( currentMonth + months * sign )
169
- newDate . setDate ( currentDate - monthDateCorrection + days * sign )
170
- const yearDiff = newDate . getFullYear ( ) - relativeTo . getFullYear ( )
171
- const monthDiff = newDate . getMonth ( ) - relativeTo . getMonth ( )
172
- const daysDiff = Math . abs ( Math . round ( ( Number ( newDate ) - Number ( relativeTo ) ) / 86400000 ) ) + monthDateCorrection
173
- const monthsDiff = Math . abs ( yearDiff * 12 + monthDiff )
174
- if ( daysDiff < 27 ) {
175
- if ( days >= 6 ) {
176
- weeks += Math . round ( days / 7 )
177
- days = 0
138
+ const referenceDate = new Date ( relativeTo )
139
+ const specifiedDate = applyDuration ( referenceDate , duration )
140
+ const [ sign , subtrahend , minuend ] =
141
+ specifiedDate < referenceDate ? [ - 1 , referenceDate , specifiedDate ] : [ 1 , specifiedDate , referenceDate ]
142
+ const subtrahendWithoutTime = new Date ( subtrahend )
143
+ subtrahendWithoutTime . setHours ( 0 )
144
+ subtrahendWithoutTime . setMinutes ( 0 )
145
+ subtrahendWithoutTime . setSeconds ( 0 )
146
+ subtrahendWithoutTime . setMilliseconds ( 0 )
147
+ const minuendWithoutTime = new Date ( minuend )
148
+ minuendWithoutTime . setHours ( 0 )
149
+ minuendWithoutTime . setMinutes ( 0 )
150
+ minuendWithoutTime . setSeconds ( 0 )
151
+ minuendWithoutTime . setMilliseconds ( 0 )
152
+ if (
153
+ subtrahendWithoutTime . getTime ( ) === minuendWithoutTime . getTime ( ) ||
154
+ subtrahend . getTime ( ) - minuend . getTime ( ) < 1000 * 60 * 60 * 12
155
+ ) {
156
+ const difference = Math . round ( ( subtrahend . getTime ( ) - minuend . getTime ( ) ) / 1000 )
157
+ let hours = Math . floor ( difference / 3600 )
158
+ let minutes = Math . floor ( ( difference % 3600 ) / 60 )
159
+ const seconds = Math . floor ( difference % 60 )
160
+ if ( hours === 0 ) {
161
+ if ( seconds >= durationRoundingThresholds [ 5 ] ) minutes += 1
162
+ if ( minutes >= durationRoundingThresholds [ 4 ] ) {
163
+ return new Duration ( 0 , 0 , 0 , 0 , 1 * sign ) // 1 hour.
164
+ }
165
+ if ( minutes === 0 ) {
166
+ return new Duration ( 0 , 0 , 0 , 0 , 0 , 0 , seconds * sign )
178
167
} else {
179
- days = daysDiff
168
+ return new Duration ( 0 , 0 , 0 , 0 , 0 , minutes * sign )
180
169
}
181
- months = years = 0
182
- } else if ( monthsDiff <= 11 ) {
183
- months = monthsDiff
184
- years = 0
185
170
} else {
186
- months = 0
187
- years = yearDiff * sign
171
+ if ( hours < 23 && minutes >= durationRoundingThresholds [ 4 ] ) hours += 1
172
+ return new Duration ( 0 , 0 , 0 , 0 , hours * sign )
188
173
}
189
- if ( months || years ) days = 0
190
174
}
191
- if ( years ) months = 0
192
-
193
- if ( weeks >= 4 ) months += Math . round ( weeks / 4 )
194
- if ( months || years ) weeks = 0
195
- if ( days && weeks && ! months && ! years ) {
196
- weeks += Math . round ( days / 7 )
197
- days = 0
175
+ const days = Math . round ( ( subtrahendWithoutTime . getTime ( ) - minuendWithoutTime . getTime ( ) ) / ( 1000 * 60 * 60 * 24 ) )
176
+ const months =
177
+ subtrahend . getFullYear ( ) * 12 + subtrahend . getMonth ( ) - ( minuend . getFullYear ( ) * 12 + minuend . getMonth ( ) )
178
+ if ( months === 0 || days <= 26 ) {
179
+ if ( days >= 6 ) {
180
+ return new Duration ( 0 , 0 , Math . floor ( ( days + 1 ) / 7 ) * sign ) // Weeks.
181
+ } else {
182
+ return new Duration ( 0 , 0 , 0 , days * sign )
183
+ }
184
+ }
185
+ if ( months < 12 ) {
186
+ return new Duration ( 0 , months * sign )
187
+ } else {
188
+ return new Duration ( ( subtrahend . getFullYear ( ) - minuend . getFullYear ( ) ) * sign )
198
189
}
199
-
200
- return new Duration (
201
- years * sign ,
202
- months * sign ,
203
- weeks * sign ,
204
- days * sign ,
205
- hours * sign ,
206
- minutes * sign ,
207
- seconds * sign ,
208
- milliseconds * sign ,
209
- )
210
190
}
211
191
212
192
export function getRelativeTimeUnit (
0 commit comments