1Code.require_file("../test_helper.exs", __DIR__) 2Code.require_file("holocene.exs", __DIR__) 3Code.require_file("fakes.exs", __DIR__) 4 5defmodule NaiveDateTimeTest do 6 use ExUnit.Case, async: true 7 doctest NaiveDateTime 8 9 test "sigil_N" do 10 assert ~N[2000-01-01T12:34:56] == 11 %NaiveDateTime{ 12 calendar: Calendar.ISO, 13 year: 2000, 14 month: 1, 15 day: 1, 16 hour: 12, 17 minute: 34, 18 second: 56 19 } 20 21 assert ~N[2000-01-01T12:34:56 Calendar.Holocene] == 22 %NaiveDateTime{ 23 calendar: Calendar.Holocene, 24 year: 2000, 25 month: 1, 26 day: 1, 27 hour: 12, 28 minute: 34, 29 second: 56 30 } 31 32 assert ~N[2000-01-01 12:34:56] == 33 %NaiveDateTime{ 34 calendar: Calendar.ISO, 35 year: 2000, 36 month: 1, 37 day: 1, 38 hour: 12, 39 minute: 34, 40 second: 56 41 } 42 43 assert ~N[2000-01-01 12:34:56 Calendar.Holocene] == 44 %NaiveDateTime{ 45 calendar: Calendar.Holocene, 46 year: 2000, 47 month: 1, 48 day: 1, 49 hour: 12, 50 minute: 34, 51 second: 56 52 } 53 54 assert_raise ArgumentError, 55 ~s/cannot parse "2001-50-50T12:34:56" as NaiveDateTime for Calendar.ISO, reason: :invalid_date/, 56 fn -> Code.eval_string("~N[2001-50-50T12:34:56]") end 57 58 assert_raise ArgumentError, 59 ~s/cannot parse "2001-01-01T12:34:65" as NaiveDateTime for Calendar.ISO, reason: :invalid_time/, 60 fn -> Code.eval_string("~N[2001-01-01T12:34:65]") end 61 62 assert_raise ArgumentError, 63 ~s/cannot parse "20010101 123456" as NaiveDateTime for Calendar.ISO, reason: :invalid_format/, 64 fn -> Code.eval_string(~s{~N[20010101 123456]}) end 65 66 assert_raise ArgumentError, 67 ~s/cannot parse "2001-01-01 12:34:56 notalias" as NaiveDateTime for Calendar.ISO, reason: :invalid_format/, 68 fn -> Code.eval_string("~N[2001-01-01 12:34:56 notalias]") end 69 70 assert_raise ArgumentError, 71 ~s/cannot parse "2001-01-01T12:34:56 notalias" as NaiveDateTime for Calendar.ISO, reason: :invalid_format/, 72 fn -> Code.eval_string("~N[2001-01-01T12:34:56 notalias]") end 73 74 assert_raise ArgumentError, 75 ~s/cannot parse "2001-50-50T12:34:56" as NaiveDateTime for Calendar.Holocene, reason: :invalid_date/, 76 fn -> Code.eval_string("~N[2001-50-50T12:34:56 Calendar.Holocene]") end 77 78 assert_raise ArgumentError, 79 ~s/cannot parse "2001-01-01T12:34:65" as NaiveDateTime for Calendar.Holocene, reason: :invalid_time/, 80 fn -> Code.eval_string("~N[2001-01-01T12:34:65 Calendar.Holocene]") end 81 82 assert_raise UndefinedFunctionError, fn -> 83 Code.eval_string("~N[2001-01-01 12:34:56 UnknownCalendar]") 84 end 85 86 assert_raise UndefinedFunctionError, fn -> 87 Code.eval_string("~N[2001-01-01T12:34:56 UnknownCalendar]") 88 end 89 end 90 91 test "to_string/1" do 92 assert to_string(~N[2000-01-01 23:00:07.005]) == "2000-01-01 23:00:07.005" 93 assert NaiveDateTime.to_string(~N[2000-01-01 23:00:07.005]) == "2000-01-01 23:00:07.005" 94 95 ndt = %{~N[2000-01-01 23:00:07.005] | calendar: FakeCalendar} 96 assert to_string(ndt) == "1/1/2000F23::0::7" 97 end 98 99 test "inspect/1" do 100 assert inspect(~N[2000-01-01 23:00:07.005]) == "~N[2000-01-01 23:00:07.005]" 101 assert inspect(~N[-0100-12-31 23:00:07.005]) == "~N[-0100-12-31 23:00:07.005]" 102 103 ndt = %{~N[2000-01-01 23:00:07.005] | calendar: FakeCalendar} 104 assert inspect(ndt) == "~N[1/1/2000F23::0::7 FakeCalendar]" 105 end 106 107 test "compare/2" do 108 ndt1 = ~N[2000-04-16 13:30:15.0049] 109 ndt2 = ~N[2000-04-16 13:30:15.0050] 110 ndt3 = ~N[2001-04-16 13:30:15.0050] 111 ndt4 = ~N[-0001-04-16 13:30:15.004] 112 assert NaiveDateTime.compare(ndt1, ndt1) == :eq 113 assert NaiveDateTime.compare(ndt1, ndt2) == :lt 114 assert NaiveDateTime.compare(ndt2, ndt1) == :gt 115 assert NaiveDateTime.compare(ndt3, ndt1) == :gt 116 assert NaiveDateTime.compare(ndt3, ndt2) == :gt 117 assert NaiveDateTime.compare(ndt4, ndt4) == :eq 118 assert NaiveDateTime.compare(ndt1, ndt4) == :gt 119 assert NaiveDateTime.compare(ndt4, ndt3) == :lt 120 end 121 122 test "to_iso8601/1" do 123 ndt = ~N[2000-04-16 12:34:15.1234] 124 ndt = put_in(ndt.calendar, FakeCalendar) 125 126 message = 127 "cannot convert #{inspect(ndt)} to target calendar Calendar.ISO, " <> 128 "reason: #{inspect(ndt.calendar)} and Calendar.ISO have different day rollover moments, " <> 129 "making this conversion ambiguous" 130 131 assert_raise ArgumentError, message, fn -> 132 NaiveDateTime.to_iso8601(ndt) 133 end 134 end 135 136 test "add/2 with other calendars" do 137 assert ~N[2000-01-01 12:34:15.123456] 138 |> NaiveDateTime.convert!(Calendar.Holocene) 139 |> NaiveDateTime.add(10, :second) == 140 %NaiveDateTime{ 141 calendar: Calendar.Holocene, 142 year: 12000, 143 month: 1, 144 day: 1, 145 hour: 12, 146 minute: 34, 147 second: 25, 148 microsecond: {123_456, 6} 149 } 150 end 151 152 test "add/2 with datetime" do 153 dt = %DateTime{ 154 year: 2000, 155 month: 2, 156 day: 29, 157 zone_abbr: "CET", 158 hour: 23, 159 minute: 0, 160 second: 7, 161 microsecond: {0, 0}, 162 utc_offset: 3600, 163 std_offset: 0, 164 time_zone: "Europe/Warsaw" 165 } 166 167 assert NaiveDateTime.add(dt, 21, :second) == ~N[2000-02-29 23:00:28] 168 end 169 170 test "diff/2 with other calendars" do 171 assert ~N[2000-01-01 12:34:15.123456] 172 |> NaiveDateTime.convert!(Calendar.Holocene) 173 |> NaiveDateTime.add(10, :second) 174 |> NaiveDateTime.diff(~N[2000-01-01 12:34:15.123456]) == 10 175 end 176 177 test "diff/2 with datetime" do 178 dt = %DateTime{ 179 year: 2000, 180 month: 2, 181 day: 29, 182 zone_abbr: "CET", 183 hour: 23, 184 minute: 0, 185 second: 7, 186 microsecond: {0, 0}, 187 utc_offset: 3600, 188 std_offset: 0, 189 time_zone: "Europe/Warsaw" 190 } 191 192 assert NaiveDateTime.diff(%{dt | second: 57}, dt, :second) == 50 193 end 194 195 test "convert/2" do 196 assert NaiveDateTime.convert(~N[2000-01-01 12:34:15.123400], Calendar.Holocene) == 197 {:ok, Calendar.Holocene.naive_datetime(12000, 1, 1, 12, 34, 15, {123_400, 6})} 198 199 assert ~N[2000-01-01 12:34:15] 200 |> NaiveDateTime.convert!(Calendar.Holocene) 201 |> NaiveDateTime.convert!(Calendar.ISO) == ~N[2000-01-01 12:34:15] 202 203 assert ~N[2000-01-01 12:34:15.123456] 204 |> NaiveDateTime.convert!(Calendar.Holocene) 205 |> NaiveDateTime.convert!(Calendar.ISO) == ~N[2000-01-01 12:34:15.123456] 206 207 assert NaiveDateTime.convert(~N[2016-02-03 00:00:01], FakeCalendar) == 208 {:error, :incompatible_calendars} 209 210 assert NaiveDateTime.convert(~N[1970-01-01 00:00:00], Calendar.Holocene) == 211 {:ok, Calendar.Holocene.naive_datetime(11970, 1, 1, 0, 0, 0, {0, 0})} 212 213 assert NaiveDateTime.convert(DateTime.from_unix!(0, :second), Calendar.Holocene) == 214 {:ok, Calendar.Holocene.naive_datetime(11970, 1, 1, 0, 0, 0, {0, 0})} 215 end 216 217 test "truncate/2" do 218 assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.123456], :microsecond) == 219 ~N[2017-11-06 00:23:51.123456] 220 221 assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.0], :millisecond) == 222 ~N[2017-11-06 00:23:51.0] 223 224 assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.999], :millisecond) == 225 ~N[2017-11-06 00:23:51.999] 226 227 assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.1009], :millisecond) == 228 ~N[2017-11-06 00:23:51.100] 229 230 assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.123456], :millisecond) == 231 ~N[2017-11-06 00:23:51.123] 232 233 assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.000456], :millisecond) == 234 ~N[2017-11-06 00:23:51.000] 235 236 assert NaiveDateTime.truncate(~N[2017-11-06 00:23:51.123456], :second) == 237 ~N[2017-11-06 00:23:51] 238 end 239 240 test "truncate/2 with datetime" do 241 dt = %DateTime{ 242 year: 2000, 243 month: 2, 244 day: 29, 245 zone_abbr: "CET", 246 hour: 23, 247 minute: 0, 248 second: 7, 249 microsecond: {3000, 6}, 250 utc_offset: 3600, 251 std_offset: 0, 252 time_zone: "Europe/Warsaw" 253 } 254 255 assert NaiveDateTime.truncate(dt, :millisecond) == ~N[2000-02-29 23:00:07.003] 256 assert catch_error(NaiveDateTime.truncate(~T[00:00:00.000000], :millisecond)) 257 end 258 259 describe "utc_now/1" do 260 test "utc_now/1 with default calendar (ISO)" do 261 naive_datetime = NaiveDateTime.utc_now() 262 assert naive_datetime.year >= 2019 263 end 264 265 test "utc_now/1 with alternative calendar" do 266 naive_datetime = NaiveDateTime.utc_now(Calendar.Holocene) 267 assert naive_datetime.calendar == Calendar.Holocene 268 assert naive_datetime.year >= 12019 269 end 270 end 271 272 describe "local_now/1" do 273 test "local_now/1 with default calendar (ISO)" do 274 naive_datetime = NaiveDateTime.local_now() 275 assert naive_datetime.year >= 2018 276 end 277 278 test "local_now/1 alternative calendar" do 279 naive_datetime = NaiveDateTime.local_now(Calendar.Holocene) 280 assert naive_datetime.calendar == Calendar.Holocene 281 assert naive_datetime.year >= 12018 282 end 283 284 test "local_now/1 incompatible calendar" do 285 assert_raise ArgumentError, 286 ~s(cannot get "local now" in target calendar FakeCalendar, reason: cannot convert from Calendar.ISO to FakeCalendar.), 287 fn -> 288 NaiveDateTime.local_now(FakeCalendar) 289 end 290 end 291 end 292 293 describe "to_date/2" do 294 test "downcasting" do 295 dt = %DateTime{ 296 year: 2000, 297 month: 2, 298 day: 29, 299 zone_abbr: "CET", 300 hour: 23, 301 minute: 0, 302 second: 7, 303 microsecond: {3000, 6}, 304 utc_offset: 3600, 305 std_offset: 0, 306 time_zone: "Europe/Warsaw" 307 } 308 309 assert NaiveDateTime.to_date(dt) == ~D[2000-02-29] 310 end 311 312 test "upcasting" do 313 assert catch_error(NaiveDateTime.to_date(~D[2000-02-29])) 314 end 315 end 316 317 describe "to_time/2" do 318 test "downcasting" do 319 dt = %DateTime{ 320 year: 2000, 321 month: 2, 322 day: 29, 323 zone_abbr: "CET", 324 hour: 23, 325 minute: 0, 326 second: 7, 327 microsecond: {3000, 6}, 328 utc_offset: 3600, 329 std_offset: 0, 330 time_zone: "Europe/Warsaw" 331 } 332 333 assert NaiveDateTime.to_time(dt) == ~T[23:00:07.003000] 334 end 335 336 test "upcasting" do 337 assert catch_error(NaiveDateTime.to_time(~T[00:00:00.000000])) 338 end 339 end 340end 341