7.2? 日期和時(shí)間元素
本小節(jié)將為讀者介紹如何對(duì)指定日期和時(shí)間元素的數(shù)值進(jìn)行提取,另外如何通過(guò)datetime的屬性來(lái)對(duì)指定的元素進(jìn)行賦值。MATLAB提供了如下函數(shù)進(jìn)行元素操作,請(qǐng)見(jiàn)表3-12。
表3-12日期和時(shí)間元素提取函數(shù)
函?數(shù)說(shuō)?明函?數(shù)說(shuō)?明
year年份minute分鐘
hour小時(shí)second秒
day日quarter季度數(shù)
month月份week星期數(shù)
ymd???年月日hms???時(shí)分秒
split???將日歷時(shí)間長(zhǎng)度按單位級(jí)別分解為數(shù)值形式time???將日歷時(shí)間長(zhǎng)度轉(zhuǎn)換為固定時(shí)間長(zhǎng)度
timeofday將時(shí)間點(diǎn)轉(zhuǎn)換為時(shí)間長(zhǎng)度isdst??檢測(cè)夏令時(shí)元素
isweekend檢測(cè)是否是周末?tzoffset檢測(cè)時(shí)區(qū),返回和UTC的時(shí)差
下面我們舉例來(lái)說(shuō)明如何從已有的datetime數(shù)組中提取日期和時(shí)間元素。然后將會(huì)介紹如何對(duì)指定元素通過(guò)對(duì)數(shù)組屬性的設(shè)置來(lái)進(jìn)行修改。
【例3-45】?日期和時(shí)間數(shù)組元素的提取。
首先創(chuàng)建一個(gè)測(cè)試用datetime數(shù)組。
>> t = datetime('now') + calyears(0:2) +calmonths(0:2) + hours(20:20:60)
t =
??04-Sep-2014 20:42:32?? 05-Oct-201516:42:32?? 06-Nov-2016 12:42:32
如果想提取數(shù)組中的“年”這一元素,那么只需要使用“.”這一符號(hào)加Year屬性就可以了。
>> t_years = t.Year
t_years =
???????2014??????? 2015??????? 2016
輸出的t_years是一個(gè)數(shù)值數(shù)組。
同樣的,如果想提取月這一元素,可以通過(guò)以下方法:
>> t_months = t.Month
t_months =
???? 9??? 10???11
在以上方法之外,用戶可以通過(guò)函數(shù)來(lái)對(duì)日期和時(shí)間的各元素進(jìn)行檢索。例如要檢索月份的話,那么就可以通過(guò)month函數(shù)來(lái)實(shí)現(xiàn)。
>> m = month(t)
m =
???? 9??? 10???11
通過(guò)使用month函數(shù)而不是Month屬性來(lái)提取月份的全名:
>> m = month(t,'name')
m =
???'September'??? 'October'??? 'November'
同樣的也可以使用year,quarter,week,hour,minute和second函數(shù)來(lái)分別提取時(shí)間數(shù)組t中的其他元素:
>> w = week(t)
w =
??? 36??? 41???46
這里返回的是數(shù)據(jù)所對(duì)應(yīng)與當(dāng)年第幾周。
使用ymd函數(shù)可以同時(shí)提取年、月、日三個(gè)元素:
>> [y,m,d] = ymd(t)
y =
???????2014??????? 2015??????? 2016
m =
???? 9??? 10???11
d =
???? 4???? 5????6
使用hms函數(shù)可以同時(shí)提取時(shí)、分、秒三個(gè)元素:
>> [h,m,s] = hms(t)
h =
??? 20??? 16???12
m =
??? 42??? 42???42
s =
??32.9365?? 32.9365?? 32.9365
【例3-46】?日期和時(shí)間數(shù)組元素的修改。
對(duì)已有時(shí)間數(shù)組中的元素?cái)?shù)值進(jìn)行修改可以通過(guò)“.”加屬性名來(lái)實(shí)現(xiàn)。
改變時(shí)間數(shù)組t中的年份,令其等于2014:
>> t.Year = 2014
t =
??04-Sep-2014 20:42:32?? 05-Oct-201416:42:32?? 06-Nov-2014 12:42:32
將時(shí)間數(shù)組t中的月份分別改成1月、2月、3月:
>> t.Month = [1,2,3]
t =
??04-Jan-2014 20:42:32?? 05-Feb-201416:42:32?? 06-Mar-2014 12:42:32
通過(guò)TimeZone屬性更改時(shí)間數(shù)組的時(shí)區(qū):
>> t.TimeZone = 'Europe/Berlin';
更改時(shí)間數(shù)組的顯示格式:
>> t.Format = 'dd-MMM-yyyy'
t =
??04-Jan-2014?? 05-Feb-2014?? 06-Mar-2014
如果用戶在賦值的時(shí)候給出的數(shù)值超出了正常范圍,那么MATLAB會(huì)對(duì)相應(yīng)的元素進(jìn)行正常化處理。例如,日期的正常范圍是1-31,如果將范圍之外的數(shù)值賦值給數(shù)組,那么結(jié)果如下:
>> t.Day = [-1 1 32]
t =
??30-Dec-2013?? 01-Feb-2014?? 01-Apr-2014
這里月份和年份的數(shù)值同時(shí)做了調(diào)整,從而使結(jié)果是屬于正常范圍的。例如這里將January -1, 2014轉(zhuǎn)化成為了December 30, 2013。
7.3? 日期和時(shí)間計(jì)算與繪圖
本小節(jié)將為讀者介紹日期和時(shí)間的相關(guān)加、減、繪圖操作。MATLAB提供了多種函數(shù)以供使用,見(jiàn)表3-13。
表3-13日期和時(shí)間計(jì)算函數(shù)
函?數(shù)說(shuō)?明函?數(shù)說(shuō)?明
between日歷代數(shù)差isdatetime判斷是否是datetime數(shù)組
caldiff日歷連續(xù)代數(shù)差isduration判斷是否是duration數(shù)組
dateshift平移日期或者產(chǎn)生日期和時(shí)間序列iscalendarduration判斷是否是calendar duration數(shù)組
isbetween判斷元素是否在日期和時(shí)間區(qū)間內(nèi)isnat??判斷是否是NaT元素(非時(shí)間元素)
【例3-47】?日歷時(shí)間長(zhǎng)度與時(shí)間數(shù)組相加。
將一個(gè)日歷時(shí)間長(zhǎng)度數(shù)組和日期January31, 2014相加:
>> t1 = datetime(2014,1,31)?????????????? %?測(cè)試時(shí)間數(shù)組
t1 =
??31-Jan-2014
>> t2 = t1 + calmonths(1:4)?????????????? %?將日歷月相加
t2 =
??28-Feb-2014?? 31-Mar-2014?? 30-Apr-2014??31-May-2014
結(jié)果中的每一個(gè)時(shí)間點(diǎn)都是當(dāng)月的最后一天。
使用caldiff?函數(shù)可以計(jì)算數(shù)組中相鄰的一對(duì)時(shí)間點(diǎn)之差:
>> dt = caldiff(t2,'days')???????????? %計(jì)算數(shù)組各時(shí)間點(diǎn)之間的日歷天數(shù)差
dt =
?? 31d?? 30d??31d
從結(jié)果中可以看出,連續(xù)的幾對(duì)時(shí)間點(diǎn)之間的差都是一個(gè)日歷月,但是天數(shù)并不都是等于31天。
同樣的我們可以對(duì)年份也進(jìn)行類似的操作:
>> t2 = t1 + calyears(0:4)????????????????? %?初始測(cè)試數(shù)組
t2 =
??31-Jan-2014?? 31-Jan-2015?? 31-Jan-2016??31-Jan-2017?? 31-Jan-2018
使用caldiff函數(shù)可以計(jì)算數(shù)組t2中相鄰時(shí)間點(diǎn)之間的天數(shù)差:
>> dt = caldiff(t2,'days')
dt =
?? 365d?? 365d??366d?? 365d
由結(jié)果可以看出,并不是每一年的天數(shù)都等于365天。
【例3-48】?計(jì)算兩個(gè)日歷時(shí)間點(diǎn)之間的時(shí)間差。
使用between函數(shù)可以計(jì)算兩個(gè)日歷時(shí)間點(diǎn)之間的年、月、日之差。
>> t1 = datetime('today')
t1 =
??02-Apr-2015
>> t2 = t1 + calmonths(0:2) + caldays(4)
t2 =
??06-Apr-2015?? 06-May-2015?? 06-Jun-2015
>> dt = between(t1,t2)
dt =
??????4d?? 1mo 4d?? 2mo 4d
【例3-49】?datetime和duration數(shù)組的比較。
本例將為讀者演示如何對(duì)datetime和duration數(shù)組進(jìn)行比較。用戶可以在兩個(gè)datetime數(shù)組之間進(jìn)行元素對(duì)元素的對(duì)比,也可以對(duì)兩個(gè)duration數(shù)組采用邏輯運(yùn)算符進(jìn)行比較,例如>和<。
對(duì)比兩個(gè)datetime數(shù)組,兩個(gè)數(shù)組必須具有相同的尺寸或者其中一個(gè)是標(biāo)量。
>> A = datetime(2013,07,26) +calyears(0:2:6)
>> B = datetime(2014,06,01)
A =
??26-Jul-2013?? 26-Jul-2015?? 26-Jul-2017??26-Jul-2019
B =
??01-Jun-2014
>> A < B
ans =
???? 1???? 0????0???? 0
在A中的時(shí)間早于B中的時(shí)間情況下,邏輯運(yùn)算符<將會(huì)返回邏輯值1(true)。
對(duì)比一個(gè)datetime數(shù)組和一個(gè)日期字符串:
>> A >= 'September 26, 2014'
ans =
???? 0???? 1????1???? 1
讀者還可以對(duì)比不同時(shí)區(qū)的時(shí)間。例如比較洛杉磯的September 1, 2014 at 4:00 p.m和同一天的紐約時(shí)間5:00p.m:
>> A = datetime(2014,09,01,16,0,0,'TimeZone','America/Los_Angeles',...
???'Format','dd-MMM-yyyy HH:mm:ss Z')
A =
??01-Sep-2014 16:00:00 -0700
>> B =datetime(2014,09,01,17,0,0,'TimeZone','America/New_York',...
???'Format','dd-MMM-yyyy HH:mm:ss Z')
B =
??01-Sep-2014 17:00:00 -0400
>> A < B
ans =
???? 0
從結(jié)果可以看出洛杉磯時(shí)間下午4點(diǎn)在紐約時(shí)間下午5點(diǎn)之后。
下面我們來(lái)對(duì)duration數(shù)組之間的比較進(jìn)行演示。
>> A = duration([2,30,30;3,15,0])?????????? %測(cè)試數(shù)據(jù)A
>> B = duration([2,40,0;2,50,0])??????????? %測(cè)試數(shù)據(jù)B
A =
?? 02:30:30
?? 03:15:00
B =
?? 02:40:00
?? 02:50:00
>> A >= B
ans =
???? 0
???? 1
從結(jié)果中可以看出,和B相比較,A的第一個(gè)元素較短,而第二個(gè)元素較長(zhǎng)。
如果將一個(gè)duration數(shù)組和一個(gè)數(shù)值型的數(shù)組進(jìn)行比較,那么數(shù)值型的數(shù)組將會(huì)被看作是天數(shù)(固定每天24小時(shí))。
>> A < [1; 1/24]???????????? %?A和【1天1小時(shí)】相比較
ans =
???? 1
???? 0
使用isbetween函數(shù)可以判斷某一日期時(shí)間是否在一個(gè)時(shí)間區(qū)間內(nèi)。
首先需要?jiǎng)?chuàng)建時(shí)間區(qū)間的兩個(gè)邊界時(shí)間點(diǎn):
>> tlower = datetime(2014,08,01)????? %?起點(diǎn)
>> tupper = datetime(2014,09,01)????? %?終點(diǎn)
tlower =
??01-Aug-2014
tupper =
??01-Sep-2014
然后創(chuàng)建一個(gè)datetime數(shù)組,然后判斷數(shù)組是否在所設(shè)定的時(shí)間區(qū)間內(nèi)。
>> A = datetime(2014,08,21) + calweeks(0:2)
A =
??21-Aug-2014?? 28-Aug-2014?? 04-Sep-2014
>> tf = isbetween(A,tlower,tupper)
tf =
???? 1???? 1????0
【例3-50】?日期和時(shí)間數(shù)組的繪圖。
首先創(chuàng)建一個(gè)datetime數(shù)組作為x軸。
>> t = datetime(2014,6,28) + caldays(1:10);
將y軸數(shù)據(jù)定義一個(gè)隨機(jī)數(shù)組,然后繪制曲線。
>> y = rand(1,10);
>> plot(t,y);
得到的結(jié)果如圖3-8所示。
圖3-8?日期數(shù)組繪圖
在默認(rèn)情況下,plot函數(shù)會(huì)基于數(shù)據(jù)的范圍自動(dòng)選擇刻度線。當(dāng)用戶放大或縮小圖形時(shí),刻度線會(huì)自動(dòng)隨之調(diào)整。另外用戶還可以自定義刻度線格式,例如通過(guò)下面的語(yǔ)句就可以將刻度線定義為日-月-年的格式。
>> plot(t,y,'DatetimeTickFormat','dd-MMM-yyyy')
得到的結(jié)果如圖3-9所示。
圖3-9?指定刻度線格式
對(duì)于duration數(shù)組來(lái)說(shuō)也可以使用類似的方式進(jìn)行繪圖。
首先創(chuàng)建一個(gè)duration數(shù)組,例如以30秒為步長(zhǎng),總時(shí)間3分鐘的一個(gè)數(shù)組:
>> t = 0:seconds(30):minutes(3);
同時(shí)創(chuàng)建隨機(jī)數(shù)組作為y軸數(shù)據(jù):
>> y = rand(1,7);
在繪圖過(guò)程中可以指定橫軸刻度均以秒為單位:
>> h = plot(t,y,'DurationTickFormat','s');
得到的結(jié)果如圖3-10所示。
7.4? 日期和時(shí)間作為數(shù)值和字符
如果用戶在使用2014a及以前版本,或者和其他使用之前版本的人共享代碼時(shí),這就需要處理存儲(chǔ)為雙精度數(shù)值或字符串形式的日期和時(shí)間數(shù)據(jù)。此外,用數(shù)值形式表示的日期和時(shí)間還可以適用于一些不接受datetime和duration數(shù)據(jù)類型的函數(shù)。
盡管datetime數(shù)組是表達(dá)時(shí)間點(diǎn)的最佳數(shù)據(jù)類型,但用戶還可以通過(guò)以下三種形式來(lái)表示日期和時(shí)間:
(1)Date String:字符串,例如Thursday, August 23, 2012?9:45:44.946 AM
(2)Date Vector:一個(gè)1×6的數(shù)值向量,包含了年、月、日、時(shí)、分、秒,例如[2012?? 8??? 23???9??? 45??? 44.946]
(3)Serial Date Number — 一個(gè)數(shù)值,從January 0, 0000開(kāi)始計(jì)算,例如7.3510e+005
采用元胞數(shù)組、矩陣等可以以數(shù)組形式存儲(chǔ)上述各種類型日期時(shí)間數(shù)據(jù)。
用戶可以使用datetime函數(shù)將上述類型數(shù)據(jù)轉(zhuǎn)換為datetime數(shù)組。反過(guò)來(lái),用戶可以分別使用datenum、datevec或datestr函數(shù)將datetime數(shù)組轉(zhuǎn)換為日期數(shù)值、日期向量或者日期字符串類型。
日期字符串就是由表示日期或者時(shí)間的字符組成,可以有多種格式,例如下面的字符串都是表示August 23, 2010 at 04:35:42 PM:
'23-Aug-2010 04:35:06 PM'
'Wednesday, August 23'
'08/23/10 16:35'
'Aug 23 16:35:42.946'
用戶可以采用12時(shí)制或者24時(shí)制來(lái)進(jìn)行記錄。在記錄的字符串中還可以加入連字符、空格、冒號(hào)來(lái)分割各個(gè)元素。例如:
>> d = '23-Aug-2010 16:35:42'
【例3-51】?日期字符串的轉(zhuǎn)換。
使用datetime函數(shù)可以將字符串轉(zhuǎn)換為datetime數(shù)組。由于輸入字符串格式可能有很多種,用戶最好指明輸入字符串的格式從而提高運(yùn)行效率。
>> t = datetime(d,'InputFormat','dd-MMM-yyyyHH:mm:ss:')
t =
??23-Aug-2010 16:35:42
盡管日期字符串d和datetime標(biāo)量t看起來(lái)非常相似,但是二者是不相同的。
>> whos d t
? Name????? Size??????????? Bytes? Class??????Attributes
? t???????? 1x1?????????????? 121? datetime??????? ??????
? d???????? 1x20?????????????? 40? char ? ??
日期向量就是一個(gè)1×6的雙精度數(shù)值的數(shù)組,其中的數(shù)值除了秒以外都是整數(shù),采用24時(shí)制的形式來(lái)表示。日期向量采用年月日時(shí)分秒的順序來(lái)進(jìn)行記錄。例如[2012? 10? 24?10? 45? 07]表示的是10:45:07AM on October 24, 2012。
【例3-52】?日期向量的轉(zhuǎn)換。
使用datetime函數(shù)將日期向量[2012? 10? 24?10? 45? 07]轉(zhuǎn)換為datetime數(shù)組。
>> t = datetime([2012? 10?24? 10? 45?07])???
t =
??24-Oct-2012 10:45:07
連續(xù)日期數(shù)值表示的是距離計(jì)時(shí)起點(diǎn)過(guò)去了多少天。在MATLAB里面,這個(gè)起點(diǎn)日期是January 0, 0000。日期數(shù)值通過(guò)小數(shù)來(lái)表示不滿一天的情況,例如6 p.m等于0.75天。所以采用日期數(shù)值來(lái)表示'31-Oct-2003, 6:00 PM'?的話那就是731885.75。
【例3-53】?日期數(shù)值的轉(zhuǎn)換。
使用datetime函數(shù)將日期數(shù)值轉(zhuǎn)換為datetime數(shù)組。
>> t =datetime(731885.75,'ConvertFrom','datenum')
t =
??31-Oct-2003 18:00:00
【例3-54】?將datetime數(shù)組轉(zhuǎn)換為日期數(shù)值。
一些MATLAB函數(shù)只接受日期數(shù)值輸入但并不接受datetime數(shù)組輸入。如果想要調(diào)用這些函數(shù)的話,那么就需要將datetime數(shù)組轉(zhuǎn)換為日期數(shù)值格式,然后再調(diào)用函數(shù)。例如log函數(shù)只接受數(shù)值格式輸入,不接受datetime數(shù)組。
假設(shè)用戶有一datetime數(shù)組表示了一項(xiàng)實(shí)驗(yàn)的時(shí)間數(shù)據(jù):
>> t = datetime('18-Jun-2014') +calmonths(1:4)
t =
??18-Jul-2014?? 18-Aug-2014?? 18-Sep-2014??18-Oct-2014
減去實(shí)驗(yàn)開(kāi)始的時(shí)間就可以得到該時(shí)間點(diǎn)對(duì)應(yīng)的實(shí)驗(yàn)所花時(shí)間長(zhǎng)度:
>> dt = t - '1-Jul-2014'
dt =
???408:00:00?? 1152:00:00?? 1896:00:00??2616:00:00
dt是一個(gè)duration數(shù)組。將dt使用years、days、hours、minutes或seconds轉(zhuǎn)換為統(tǒng)一單位的數(shù)值,例如:
>> x = hours(dt)
x =
????????408??????? 1152??????? 1896??????? 2616
將此雙精度數(shù)組輸入到log函數(shù)中就可以進(jìn)行相應(yīng)的計(jì)算:
>> y = log(x)
y =
???6.0113??? 7.0493??? 7.5475???7.8694