Skip to content

Commit 4c00c0b

Browse files
Fix: preserve datetime precision after Timex.shift/2
Resolves #731 Unfortunately this broke with elixir-lang/elixir@5a583c7 which was release with Elixir 1.14.3 Elixir 1.13.4: ``` iex(3)> DateTime.utc_now() |> IO.inspect() |> DateTime.truncate(:second) |> IO.inspect() |> Timex.shift(minutes: 1) |> IO.inspect() ~U[2023-04-13 09:56:10.136274Z] ~U[2023-04-13 09:56:10Z] ~U[2023-04-13 09:57:10Z] ``` Elixir 1.14.4: ``` iex(1)> DateTime.utc_now() |> IO.inspect() |> DateTime.truncate(:second) |> IO.inspect() |> Timex.shift(minutes: 1) |> IO.inspect() ~U[2023-04-13 09:55:16.405357Z] ~U[2023-04-13 09:55:16Z] ~U[2023-04-13 09:56:16.000000Z] ```
1 parent 7f584ce commit 4c00c0b

File tree

3 files changed

+55
-3
lines changed

3 files changed

+55
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1616

1717
- Updated `Timex.now/1` typespec to remove the `AmbiguousDateTime`
1818
- Corrected pluralization rules for bg/cs/he/id/ro/ru
19+
- Fixed `Timex.shift/2` to preserve the precision of the provided datetime
1920

2021
---
2122

lib/datetime/datetime.ex

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -447,13 +447,17 @@ defimpl Timex.Protocol, for: DateTime do
447447
err
448448

449449
%DateTime{} = datetime when shift != 0 ->
450-
DateTime.add(datetime, shift, :microsecond, Timex.Timezone.Database)
450+
datetime
451+
|> DateTime.add(shift, :microsecond, Timex.Timezone.Database)
452+
|> retain_precision(datetime)
451453

452454
%DateTime{} = datetime ->
453455
datetime
454456

455-
{{ty, _, _}, %DateTime{} = orig} when ty in [:gap, :ambiguous] and shift != 0 ->
456-
DateTime.add(orig, shift, :microsecond, Timex.Timezone.Database)
457+
{{ty, _, _}, %DateTime{} = original} when ty in [:gap, :ambiguous] and shift != 0 ->
458+
original
459+
|> DateTime.add(shift, :microsecond, Timex.Timezone.Database)
460+
|> retain_precision(datetime)
457461

458462
{{ty, _a, _b} = amb, _} when ty in [:gap, :ambiguous] ->
459463
amb
@@ -480,6 +484,13 @@ defimpl Timex.Protocol, for: DateTime do
480484
err
481485
end
482486

487+
defp retain_precision(
488+
%DateTime{microsecond: {ms, _precision}} = new_datetime,
489+
%DateTime{microsecond: {_ms, precision}} = _original_datetime
490+
) do
491+
%{new_datetime | microsecond: {ms, precision}}
492+
end
493+
483494
defp logical_shift(datetime, []), do: datetime
484495

485496
defp logical_shift(datetime, shifts) do

test/shift_test.exs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,44 @@ defmodule ShiftTests do
229229
expected = ~D[2017-12-31] |> Timex.to_datetime()
230230
assert expected === date
231231
end
232+
233+
describe "DateTime does not change precision" do
234+
test "seconds" do
235+
datetime = Timex.shift(~U[2023-04-13 08:00:00Z], minutes: 1)
236+
expected = ~U[2023-04-13 08:01:00Z]
237+
assert expected === datetime
238+
end
239+
240+
test "milliseconds" do
241+
datetime = Timex.shift(~U[2023-04-13 08:00:00.000Z], minutes: 1)
242+
expected = ~U[2023-04-13 08:01:00.000Z]
243+
assert expected === datetime
244+
end
245+
246+
test "microseconds" do
247+
datetime = Timex.shift(~U[2023-04-13 08:00:00.000000Z], minutes: 1)
248+
expected = ~U[2023-04-13 08:01:00.000000Z]
249+
assert expected === datetime
250+
end
251+
end
252+
253+
describe "NaiveDateTime does not change precision" do
254+
test "seconds" do
255+
datetime = Timex.shift(~N[2023-04-13 08:00:00Z], minutes: 1)
256+
expected = ~N[2023-04-13 08:01:00Z]
257+
assert expected === datetime
258+
end
259+
260+
test "milliseconds" do
261+
datetime = Timex.shift(~N[2023-04-13 08:00:00.000Z], minutes: 1)
262+
expected = ~N[2023-04-13 08:01:00.000Z]
263+
assert expected === datetime
264+
end
265+
266+
test "microseconds" do
267+
datetime = Timex.shift(~N[2023-04-13 08:00:00.000000Z], minutes: 1)
268+
expected = ~N[2023-04-13 08:01:00.000000Z]
269+
assert expected === datetime
270+
end
271+
end
232272
end

0 commit comments

Comments
 (0)