1
1
//! This module implements `DateTime` any directly related algorithms.
2
2
3
3
use super :: {
4
- duration:: normalized:: { NormalizedDurationRecord , NormalizedTimeDuration } ,
5
- Duration , PartialTime , PlainDate , PlainTime , ZonedDateTime ,
4
+ duration:: normalized:: InternalDurationRecord , Duration , PartialTime , PlainDate , PlainTime ,
5
+ ZonedDateTime ,
6
6
} ;
7
7
use crate :: parsed_intermediates:: ParsedDateTime ;
8
8
use crate :: {
@@ -19,7 +19,7 @@ use crate::{
19
19
parsers:: IxdtfStringBuilder ,
20
20
primitive:: FiniteF64 ,
21
21
provider:: { NeverProvider , TimeZoneProvider } ,
22
- temporal_assert , MonthCode , TemporalError , TemporalResult , TimeZone ,
22
+ MonthCode , TemporalError , TemporalResult , TimeZone ,
23
23
} ;
24
24
use alloc:: string:: String ;
25
25
use core:: { cmp:: Ordering , str:: FromStr } ;
@@ -225,33 +225,25 @@ impl PlainDateTime {
225
225
overflow : Option < ArithmeticOverflow > ,
226
226
) -> TemporalResult < Self > {
227
227
// SKIP: 1, 2, 3, 4
228
- // 1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
229
- // 2. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
230
- // 3. Set options to ? GetOptionsObject(options).
231
- // 4. Let calendarRec be ? CreateCalendarMethodsRecord(dateTime.[[Calendar]], « date-add »).
232
-
233
- // 5. Let norm be NormalizeTimeDuration(sign × duration.[[Hours]], sign × duration.[[Minutes]], sign × duration.[[Seconds]], sign × duration.[[Milliseconds]], sign × duration.[[Microseconds]], sign × duration.[[Nanoseconds]]).
234
- let norm = NormalizedTimeDuration :: from_time_duration ( duration. time ( ) ) ;
235
-
236
- // TODO: validate Constrain is default with all the recent changes.
237
- // 6. Let result be ? AddDateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], calendarRec, sign × duration.[[Years]], sign × duration.[[Months]], sign × duration.[[Weeks]], sign × duration.[[Days]], norm, options).
238
- let result =
239
- self . iso
240
- . add_date_duration ( self . calendar ( ) . clone ( ) , duration. date ( ) , norm, overflow) ?;
241
-
242
- // 7. Assert: IsValidISODate(result.[[Year]], result.[[Month]], result.[[Day]]) is true.
243
- // 8. Assert: IsValidTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]],
244
- // result.[[Microsecond]], result.[[Nanosecond]]) is true.
245
- temporal_assert ! (
246
- result. is_within_limits( ) ,
247
- "Assertion failed: the below datetime is not within valid limits:\n {:?}" ,
248
- result
249
- ) ;
250
-
251
- // 9. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]],
252
- // result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]],
253
- // result.[[Nanosecond]], dateTime.[[Calendar]]).
254
- Ok ( Self :: new_unchecked ( result, self . calendar . clone ( ) ) )
228
+ // 5. Let internalDuration be ToInternalDurationRecordWith24HourDays(duration).
229
+ let internal_duration = InternalDurationRecord :: from_duration_with_24_hour_days ( duration) ?;
230
+ // 6. Let timeResult be AddTime(dateTime.[[ISODateTime]].[[Time]], internalDuration.[[Time]]).
231
+ let ( days, time_result) = self
232
+ . iso
233
+ . time
234
+ . add ( internal_duration. normalized_time_duration ( ) ) ;
235
+ // 7. Let dateDuration be ? AdjustDateDurationRecord(internalDuration.[[Date]], timeResult.[[Days]]).
236
+ let date_duration = internal_duration. date ( ) . adjust ( days, None , None ) ?;
237
+ // 8. Let addedDate be ? CalendarDateAdd(dateTime.[[Calendar]], dateTime.[[ISODateTime]].[[ISODate]], dateDuration, overflow).
238
+ let added_date = self . calendar ( ) . date_add (
239
+ & self . iso . date ,
240
+ & date_duration,
241
+ overflow. unwrap_or ( ArithmeticOverflow :: Constrain ) ,
242
+ ) ?;
243
+ // 9. Let result be CombineISODateAndTimeRecord(addedDate, timeResult).
244
+ let result = IsoDateTime :: new ( added_date. iso , time_result) ?;
245
+ // 10. Return ? CreateTemporalDateTime(result, dateTime.[[Calendar]]).
246
+ Ok ( Self :: new_unchecked ( result, self . calendar ( ) . clone ( ) ) )
255
247
}
256
248
257
249
/// Difference two `DateTime`s together.
@@ -284,7 +276,7 @@ impl PlainDateTime {
284
276
// Step 10-11.
285
277
let norm_record = self . diff_dt_with_rounding ( other, options) ?;
286
278
287
- let result = Duration :: from_normalized ( norm_record, options. largest_unit ) ?;
279
+ let result = Duration :: from_internal ( norm_record, options. largest_unit ) ?;
288
280
289
281
// Step 12
290
282
match op {
@@ -300,12 +292,12 @@ impl PlainDateTime {
300
292
& self ,
301
293
other : & Self ,
302
294
options : ResolvedRoundingOptions ,
303
- ) -> TemporalResult < NormalizedDurationRecord > {
295
+ ) -> TemporalResult < InternalDurationRecord > {
304
296
// 1. If CompareISODateTime(y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2) = 0, then
305
297
if matches ! ( self . iso. cmp( & other. iso) , Ordering :: Equal ) {
306
298
// a. Let durationRecord be CreateDurationRecord(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
307
299
// b. Return the Record { [[DurationRecord]]: durationRecord, [[Total]]: 0 }.
308
- return Ok ( NormalizedDurationRecord :: default ( ) ) ;
300
+ return Ok ( InternalDurationRecord :: default ( ) ) ;
309
301
}
310
302
// 2. If ISODateTimeWithinLimits(isoDateTime1) is false or ISODateTimeWithinLimits(isoDateTime2) is false, throw a RangeError exception.
311
303
self . iso . check_validity ( ) ?;
@@ -1248,13 +1240,13 @@ mod tests {
1248
1240
PlainDateTime :: try_new ( 2019 , 10 , 29 , 10 , 46 , 38 , 271 , 986 , 102 , Calendar :: default ( ) )
1249
1241
. unwrap ( ) ;
1250
1242
1251
- let result = dt. subtract ( & Duration :: hour ( 12 ) , None ) . unwrap ( ) ;
1243
+ let result = dt. subtract ( & Duration :: from_hours ( 12 ) , None ) . unwrap ( ) ;
1252
1244
assert_datetime (
1253
1245
result,
1254
1246
( 2019 , 10 , tinystr ! ( 4 , "M10" ) , 28 , 22 , 46 , 38 , 271 , 986 , 102 ) ,
1255
1247
) ;
1256
1248
1257
- let result = dt. add ( & Duration :: hour ( -12 ) , None ) . unwrap ( ) ;
1249
+ let result = dt. add ( & Duration :: from_hours ( -12 ) , None ) . unwrap ( ) ;
1258
1250
assert_datetime (
1259
1251
result,
1260
1252
( 2019 , 10 , tinystr ! ( 4 , "M10" ) , 28 , 22 , 46 , 38 , 271 , 986 , 102 ) ,
@@ -1543,4 +1535,21 @@ mod tests {
1543
1535
"pads 4 decimal places to 9"
1544
1536
) ;
1545
1537
}
1538
+
1539
+ #[ test]
1540
+ fn datetime_add ( ) {
1541
+ use crate :: { Duration , PlainDateTime } ;
1542
+ use core:: str:: FromStr ;
1543
+
1544
+ let dt = PlainDateTime :: from_str ( "2024-01-15T12:00:00" ) . unwrap ( ) ;
1545
+
1546
+ let duration = Duration :: from_str ( "P1M2DT3H4M" ) . unwrap ( ) ;
1547
+
1548
+ // Add duration
1549
+ let later = dt. add ( & duration, None ) . unwrap ( ) ;
1550
+ assert_eq ! ( later. month( ) , 2 ) ;
1551
+ assert_eq ! ( later. day( ) , 17 ) ;
1552
+ assert_eq ! ( later. hour( ) , 15 ) ;
1553
+ assert_eq ! ( later. minute( ) , 4 ) ;
1554
+ }
1546
1555
}
0 commit comments