跳至內容

介紹 Julia/使用日期和時間

來自 Wikibooks,開放世界中的開放書籍
Previous page
使用文字檔案
介紹 Julia Next page
繪圖
使用日期和時間

使用日期和時間

[編輯 | 編輯原始碼]

用於處理日期和時間的函式在標準包 Dates 中提供。要使用任何時間和日期函式,您必須執行以下操作之一

  • using Dates
  • import Dates

如果您使用 import Dates 函式,則需要在每個函式前面加上明確的 Dates. 字首,例如 Dates.dayofweek(dt),如本章所示。但是,如果您在程式碼中新增 using Dates 行,這會將所有匯出的 Dates 函式引入 Main,並且可以使用它們而無需 Dates. 字首。

此圖顯示了用於儲存時間、日期和日期時間的各種型別之間的關係。

Shows the hierarchy of date and date-time types in Julia
顯示了 Julia 中日期和日期時間型別的層次結構

日期、時間和日期時間

[編輯 | 編輯原始碼]

有三種主要的資料型別可用

  • Dates.Time 物件表示一天中的一個精確時間點。它沒有說明星期幾或年份。它的精度為納秒。
  • Dates.Date 物件只表示日期:沒有時區,沒有夏令時問題等... 它的精度為一天。
  • Dates.DateTime 物件是日期和時間組合,因此它指定了時間中的一個確切時刻。它的精度為毫秒左右。

使用這些建構函式之一來建立您想要的物件型別

julia> rightnow = Dates.Time(Dates.now()) # a Dates.Time object
16:51:56.374
julia> birthday = Dates.Date(1997,3,15)   # a Dates.Date object
1997-03-15

julia> armistice = Dates.DateTime(1918,11,11,11,11,11) # a Dates.DateTime object
1918-11-11T11:11:11

Dates.today() 函式返回當前日期的 Date 物件

julia> datetoday = Dates.today()
2014-09-02

Dates.now() 函式返回當前時間點的 DateTime 物件

julia> datetimenow = Dates.now()
2014-09-02T08:20:07.437

(我們之前使用 Dates.now() 來定義 rightnow,然後使用 Dates.Time() 將其轉換為 Dates.Time。)

有時您需要 UTC(世界參考時間,沒有本地夏令時調整)

julia> Dates.now(Dates.UTC)
2014-09-02T08:27:54.14

要從格式化字串建立物件,請在 Dates 中使用 DateTime() 函式,並提供一個與格式匹配的合適格式字串

julia> Dates.DateTime("20140529 120000", "yyyymmdd HHMMSS")
2014-05-29T12:00:00

julia> Dates.DateTime("18/05/2009 16:12", "dd/mm/yyyy HH:MM")
2009-05-18T16:12:00

julia> vacation = Dates.DateTime("2014-09-02T08:20:07") # defaults to expecting ISO8601 format
2014-09-02T08:20:07

有關更多示例,請參閱下面的 日期格式化

日期和時間查詢

[編輯 | 編輯原始碼]

獲得日期/時間或日期物件後,您可以使用以下函式從該物件中提取資訊。對於日期和日期時間物件,您可以獲取年份、月份、日期等等

julia> Dates.year(birthday)
1997

julia> Dates.year(datetoday)
2014

julia> Dates.month(birthday)
3

julia> Dates.month(datetoday)
9

julia> Dates.day(birthday)
15

julia> Dates.day(datetoday)
2

以及,對於日期/時間物件

julia> Dates.minute(now())
37

julia> Dates.hour(now())
16

julia> Dates.second(now())
8
julia> Dates.minute(rightnow)
37

julia> Dates.hour(rightnow)
16

julia> Dates.second(rightnow)
8

還有一堆其他有用的函式

julia> Dates.dayofweek(birthday)
6

julia> Dates.dayname(birthday)
"Saturday"

julia> Dates.yearmonth(now())
(2014,9)

julia> Dates.yearmonthday(birthday)
(1997,3,15)

julia> Dates.isleapyear(birthday)
false

julia> Dates.daysofweekinmonth(datetoday)
5

julia> Dates.monthname(birthday)
"March"

julia> Dates.monthday(now())
(9,2)

julia> Dates.dayofweekofmonth(birthday)
3 

其中兩個函式的名稱非常相似:Dates.daysofweekinmonth()(月份中的星期幾)函式告訴您一個月中與指定日期具有相同日期名稱的天數 - 本月(撰寫本文時)有五個星期二。最後一個函式 dayofweekofmonth(birthday)(月份中的星期幾)告訴我們,1997 年 3 月 15 日是這個月的第三個星期六。

您還可以查詢相對於某個日期的日期,例如包含該日期的第一個星期幾,方法是使用下面介紹的調整函式。

日期運算

[編輯 | 編輯原始碼]

您可以對日期和日期/時間物件進行運算。減去兩個日期或日期時間以找到差異是最明顯的一種

julia> datetoday - birthday
6380 days

julia> datetimenow - armistice
3023472252000 milliseconds

您可以將其轉換為 Dates.DayDates.Millisecond 或其他單位

julia> Dates.Period(datetoday - birthday)
7357 days

julia> Dates.canonicalize(Dates.CompoundPeriod(datetimenow - armistice))
5138 weeks, 5 days, 5 hours, 46 minutes, 1 second, 541 milliseconds

julia> convert(Dates.Day, Dates.Period(Dates.today() - Dates.Date(2016, 1, 1)))
491 days

julia> convert(Dates.Millisecond, Dates.Period(Dates.today() - Dates.Date(2016, 1, 1)))
42422400000 milliseconds

要向日期和日期/時間物件新增和減去時間段,請使用 Dates. 建構函式來指定時間段。例如,Dates.Year(20) 定義了 20 年的時間段,Dates.Month(6) 定義了 6 個月的時間段。因此,要向生日日期新增 20 年和 6 個月

julia> birthday + Dates.Year(20) + Dates.Month(6)
2017-09-15

這是從現在起 6 個月前

julia> Dates.now() - Dates.Month(6)
2014-03-02T16:43:08

類似地,對於月份、周

julia> Dates.now() - Dates.Year(2) - Dates.Month(6)
2012-03-02T16:44:03

類似地,對於周和小時。這是從現在起兩週和 12 小時的日期和時間

julia> Dates.now() + Dates.Week(2) + Dates.Hour(12)
2015-09-18T20:49:16

還有

julia> daystoxmas = Dates.Date(Dates.year(Dates.now()), 12, 25) - Dates.today()
148 days

或距離聖誕節還有 148 天(撰寫本文時)。

要將值檢索為數字,請使用 Dates.value() 函式

julia> Dates.value(daystoxmas)
148

這適用於不同型別的日期/時間物件

julia> lastchristmas = Dates.now() - Dates.DateTime(2017, 12, 25, 0, 0, 0)
25464746504 milliseconds

julia> Dates.value(lastchristmas)
25464746504

日期範圍

[編輯 | 編輯原始碼]

您可以建立可迭代的範圍物件來定義日期範圍

julia>  d = Dates.Date(1980,1,1):Dates.Month(3):Dates.Date(2019,1,1)
1980-01-01:3 months:2019-01-01

此迭代器會生成每三個月的第一天。要找出這些日期中的哪些日期是工作日,您可以向 filter() 提供一個匿名函式,該函式將日期名稱與給定日期名稱進行比較

julia> weekdays = filter(dy -> Dates.dayname(dy) != "Saturday" && Dates.dayname(dy) != "Sunday" , d)

104 元素 Array{Date,1}

1980-01-01
1980-04-01
1980-07-01
⋮         
2014-07-01
2014-10-01
2016-04-01
2016-07-01
2018-01-01
2018-10-01
2019-01-01

類似地,這是從現在起 3 小時間隔的時間範圍,持續一年

julia> d = collect(Dates.DateTime(Dates.now()):Dates.Hour(3):Dates.DateTime(Dates.now() + Dates.Year(1)))
2929-element Array{DateTime,1}:
2015-09-04T08:30:59
2015-09-04T11:30:59
2015-09-04T14:30:59
 ⋮                  
2016-09-03T20:30:59
2016-09-03T23:30:59
2016-09-04T02:30:59
2016-09-04T05:30:59
2016-09-04T08:30:59

如果您必須每 30 天支付一次賬單,從 2018 年 1 月 1 日開始,以下程式碼顯示了到期日期每個月是如何向前推移的

julia> foreach(d -> println(Dates.format(d, "d u yyyy")), Dates.Date("2018-01-01"):Dates.Day(30):Dates.Date("2019-01-01"))
1 Jan 2018
31 Jan 2018
2 Mar 2018
1 Apr 2018
1 May 2018
31 May 2018
30 Jun 2018
30 Jul 2018
29 Aug 2018
28 Sep 2018
28 Oct 2018
27 Nov 2018
27 Dec 2018

日期格式化

[編輯 | 編輯原始碼]

要指定日期格式,請在格式字串中使用日期格式化程式碼。每個字元都代表一個日期/時間元素

y  Year digit eg yyyy => 2015, yy => 15
m  Month digit eg m => 3 or 03
u  Month name eg Jan
U  Month name eg January
e  Day of week eg Tue
E  Day of week eg Tuesday
d  Day eg 3 or 03
H  Hour digit eg HH => 00
M  Minute digit eg MM => 00
S  Second digit eg S => 00
s  Millisecond digit eg .000

您可以將這些格式字串與 DateTime()Dates.format() 等函式一起使用。例如,您可以透過識別傳入字串中的不同元素,從字串中建立 DateTime 物件

julia> Dates.Date("Fri, 15 Jun 2018", "e, d u y")
2018-06-15
julia> Dates.DateTime("Fri, 15 Jun 2018 11:43:14", "e, d u y H:M:S")
2018-06-15T11:43:14

其他字元按字面意思使用。在第二個示例中,格式化字元匹配如下

Fri, 15 Jun 2018 11:43:14
e  ,  d   u    y  H: M: S

您可以向 Dates.format 提供格式字串來格式化日期物件。在格式字串中,您可以重複字元以控制例如年份和日期的輸出方式

julia> timenow = Dates.now()
2015-07-28T11:43:14
julia> Dates.format(timenow, "e, dd u yyyy HH:MM:SS")
"Tue, 28 Jul 2015 11:43:14"

建立格式化日期時,您可以將格式字串中的某些元件加倍,以對一位數日期元素生成前導零

julia> anothertime = Dates.DateTime("Tue, 8 Jul 2015 2:3:7", "e, d u y H:M:S")
2015-07-08T02:03:07

julia> Dates.format(anothertime, "e: dd u yy, HH.MM.SS") # with leading zeros
"Wed: 08 Jul 15, 02.03.07"

julia> Dates.format(anothertime, "e: d u yy, H.M.S")
"Wed: 8 Jul 15, 2.3.7"

要將日期字串從一種格式轉換為另一種格式,您可以使用 DateTime() 和格式字串將字串轉換為 DateTime 物件,然後使用 DateFormat() 以不同格式輸出物件

julia> formatted_date = "Tue, 28 Jul 2015 11:43:14"
"Tue, 28 Jul 2015 11:43:14"

julia> temp = Dates.DateTime(formatted_date, "e, dd u yyyy HH:MM:SS")
2015-07-28T11:43:14

julia> Dates.format(temp, "dd, U, yyyy HH:MM, e")
"28, July, 2015 11:43, Tue"

如果您要進行大量的日期格式化(您可以將日期函式應用於字串陣列),最好預先定義一個 DateFormat 物件,然後將其用於批次轉換(這更快)

julia> dformat = Dates.DateFormat("y-m-d");

julia> Dates.Date.([   # broadcast
      "2010-01-01", 
      "2011-03-23", 
      "2012-11-3", 
      "2013-4-13", 
      "2014-9-20", 
      "2015-3-1"
      ], dformat)
6-element Array{Date,1}:
 2010-01-01
 2011-03-23
 2012-11-03
 2013-04-13
 2014-09-20
 2015-03-01

有一些內建格式可以使用。例如,有 Dates.ISODateTimeFormat 用於為您提供 ISO8601 格式

julia> Dates.DateTime.([  
          "2010-01-01", 
          "2011-03-23", 
          "2012-11-3", 
          "2013-4-13", 
          "2014-9-20", 
          "2015-3-1" 
          ], Dates.ISODateTimeFormat) 
6-element Array{DateTime,1}:
2010-01-01T00:00:00
2011-03-23T00:00:00
2012-11-03T00:00:00
2013-04-13T00:00:00
2014-09-20T00:00:00
2015-03-01T00:00:00

這是傳統的 RFC1123

julia> Dates.format(Dates.now(), Dates.RFC1123Format)
"Sat, 30 Jul 2016 16:36:09"

日期調整

[編輯 | 編輯原始碼]

有時您需要查詢最接近另一個日期的日期 - 例如,那個星期的第一天或包含那個日期的月的最後一天。您可以使用 Dates.firstdayofweek()Dates.lastdayofmonth() 等函式來完成此操作。因此,如果我們目前在週中

julia> Dates.dayname(now())
"Wednesday"

這將返回星期一

julia> Dates.firstdayofweek(now())
2014-09-01T00:00:00

您也可以使用函式鏈運算子來編寫它

julia> Dates.now() |> Dates.firstdayofweek |> Dates.dayname 
"Monday"

tofirst()tolast()tonext()toprev() 方法提供了更通用的解決方案。

使用 `tonext()` 和 `toprev()`,您可以提供一個(可能是匿名的)函式,當日期被正確調整時,該函式返回 true。例如,函式

d->Dates.dayofweek(d) == Dates.Tuesday

如果日期 `d` 是星期二,則返回 true。將此與 `tonext()` 方法一起使用

julia> Dates.tonext(d->Dates.dayofweek(d) == Dates.Tuesday, birthday)
1997-03-18 # the first Tuesday after the birthday

或者您可以找到生日日期之後的下一個星期日

julia> Dates.tonext(d->Dates.dayname(d) == "Sunday", birthday)
1997-03-16 # the first Sunday after the birthday

使用 `tofirst()` 和 `tolast()`,您可以找到一個月的第一個星期日、星期四或任何其他日期。星期一是 1,星期二 2,等等。

julia> Dates.tofirst(birthday, 1) # the first Monday (1) of that month
1997-03-03

提供關鍵字引數 `of=Year` 以獲取一年中的第一個匹配的星期幾。

julia> Dates.tofirst(birthday, 1, of=Year) # the first Monday (1) of 1997
1997-01-06

四捨五入日期和時間

[編輯 | 編輯原始碼]

您可以使用 `round()`、`floor()` 和 `ceil()`,通常用於將數字四捨五入到最近的首選值,以調整日期向前或向後,使它們具有“更圓”的值。

julia> Dates.now()
2016-09-12T17:55:11.378

julia> Dates.format(round(Dates.DateTime(Dates.now()), Dates.Minute(15)), Dates.RFC1123Format)
"Mon, 12 Sep 2016 18:00:00"

The `ceil()` 函式將日期或時間調整為向前

julia> ceil(birthday, Dates.Month)
1997-04-01

julia> ceil(birthday, Dates.Year)
1998-01-01

julia> ceil(birthday, Dates.Week)
1997-03-17

重複出現的日期

[編輯 | 編輯原始碼]

能夠找到一組日期中滿足某些特定條件的所有日期非常有用。例如,您可以使用 `Dates.dayofweekofmonth()` 和 `Dates.dayname()` 函式計算出一個月的第二個星期日。

例如,讓我們建立一個日期範圍,從 2014 年 9 月 1 日到 2014 年聖誕節

julia> dr = Dates.Date(2014,9,1):Dates.Day(1):Dates.Date(2014,12,25)
2014-09-01:1 day:2014-12-25

現在,一個類似於我們之前在 `tonext()` 中使用的匿名函式,找到該範圍內滿足該函式的日期的選擇。

julia> filter(d -> Dates.dayname(d) == "Sunday", dr)
16-element Array{Date,1}:
 2014-09-07
 2014-09-14
 2014-09-21
 2014-09-28
 2014-10-05
 2014-10-12
 2014-10-19
 2014-10-26
 2014-11-02
 2014-11-09
 2014-11-16
 2014-11-23
 2014-11-30
 2014-12-07
 2014-12-14
 2014-12-21

這些是 2014 年 9 月 1 日到 2014 年聖誕節之間的每個星期日的日期。

透過在匿名函式中組合條件,您可以構建更復雜的重複事件。這是一個列表,包含該時期內所有在奇數天且大於 20 的星期二

julia> filter(d->Dates.dayname(d) == "Tuesday" && isodd(Dates.day(d)) && Dates.day(d) > 20, dr)
4-element Array{Date,1}:
2014-09-23
2014-10-21
2014-11-25
2014-12-23

以及 2016 年 4 月至 11 月之間的每個第二個星期二

dr = Dates.Date(2015):Dates.Day(1):Dates.Date(2016);
filter(dr) do x
    Dates.dayofweek(x) == Dates.Tue &&
    Dates.April <= Dates.month(x) <= Dates.Nov &&
    Dates.dayofweekofmonth(x) == 2
end
8-element Array{Base.Dates.Date,1}:
 2015-04-14
 2015-05-12
 2015-06-09
 2015-07-14
 2015-08-11
 2015-09-08
 2015-10-13
 2015-11-10

Unix 時間

[編輯 | 編輯原始碼]

您有時必須處理另一種時間記錄方式:Unix 時間。Unix 時間是從 1970 年(Unix 的誕生)開始經過的秒數。在 Julia 中,計數儲存在一個 64 位整數中,我們永遠不會看到 Unix 時間的結束。(宇宙將在 64 位 Unix 時間達到最大可能值之前很久就結束了,這將是在 2922 億年後,即 292,277,026,596 年 12 月 4 日星期日 15:30:08)。

在 Julia 中,`time()` 函式(不帶引數使用)返回當前秒的 Unix 時間值

julia> time()
1.414141581230945e9

The `strftime()` ("string format time") function,它存在於 Libc 模組中,將 Unix 時間中的秒數轉換為更易讀的格式

julia> Libc.strftime(86400 * 365.25 * 4) # 4 years worth of Unix seconds
"Tue  1 Jan 00:00:00 1974"

您可以透過提供格式字串來選擇不同的格式,格式字串中的日期和時間不同部分由“%”字母程式碼定義

julia> Libc.strftime("%A, %B %e at %T, %Y", 86400 * 365.25 * 4)
"Tuesday, January  1 at 00:00:00, 1974"

The `strptime()` 函式接收格式字串和日期字串,並返回一個 TmStruct 表示式。然後可以透過將其傳遞給 `time()` 來將其轉換為 Unix 時間值

julia> Libc.strptime("%A, %B %e at %T, %Y", "Tuesday, January  1 at 00:00:00, 1974")
Base.Libc.TmStruct(0,0,0,1,0,74,2,0,0,0,0,0,0,0)

julia> time(ans)
1.262304e8

julia> time(Libc.strptime("%Y-%m-%d","2014-10-1"))
1.4121216e9

Dates 模組還提供了一個 `unix2datetime()` 函式,該函式將 Unix 時間值轉換為日期/時間物件

julia> Dates.unix2datetime(time())
2014-10-24T09:26:29.305

時間點

[編輯 | 編輯原始碼]

`DateTime` 以毫秒的形式儲存在 `instant` 欄位中。使用 `Dates.value` 獲取值。

julia> moment=Dates.now()
2017-02-01T12:45:46.326
  
julia> Dates.value(moment)
63621636346326
julia> moment.instant
Base.Dates.UTInstant{Base.Dates.Millisecond}(63621636346326 milliseconds)

如果您使用更精確的 `Dates.Time` 型別,您可以訪問納秒。

julia> moment = Dates.Time(Dates.now())
17:38:44.33
julia> Dates.value(moment)
63524330000000
 
julia> moment.instant
63524330000000 nanoseconds

計時和監控

[編輯 | 編輯原始碼]

The `@elapsed` 宏返回表示式求值所花費的秒數

function test(n)
     for i in 1:n
        x = sin(rand())
     end
end
julia> @elapsed test(100000000)
1.309819509

The `@time` 宏會告訴您表示式求值花費了多長時間以及分配了多少記憶體。

julia> @time test(100000000)
2.532941 seconds (4 allocations: 160 bytes)
華夏公益教科書