介紹 Julia/使用日期和時間
用於處理日期和時間的函式在標準包 Dates 中提供。要使用任何時間和日期函式,您必須執行以下操作之一
using Dates
import Dates
如果您使用 import Dates 函式,則需要在每個函式前面加上明確的 Dates. 字首,例如 Dates.dayofweek(dt),如本章所示。但是,如果您在程式碼中新增 using Dates 行,這會將所有匯出的 Dates 函式引入 Main,並且可以使用它們而無需 Dates. 字首。
此圖顯示了用於儲存時間、日期和日期時間的各種型別之間的關係。

有三種主要的資料型別可用
- 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.Day 或 Dates.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 時間是從 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)