亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Ruby日期時(shí)間的比較,日期轉(zhuǎn)換等時(shí)間日期處理方法大全

 更新時(shí)間:2022年04月18日 12:18:50   作者:駿馬金龍  
這篇文章主要介紹了Ruby的日期時(shí)間處理方法與函數(shù),日期時(shí)間和字符串、數(shù)值之間的轉(zhuǎn)換,日期時(shí)間的比較需要的朋友可以參考下

Ruby中Date、TimeDateTime這3個(gè)類提供 了和日期時(shí)間相關(guān)的操作。

Date只能處理日期
Time能處理日期和時(shí)間
DateTime也能處理日期和時(shí)間

其中,DateTime 是Date的一個(gè)子類,是對(duì)時(shí)間部分?jǐn)?shù)據(jù)的補(bǔ)充。要使用Date和DateTime類,只需導(dǎo)入date庫(kù)就可以,要使用Time類,導(dǎo)入time庫(kù)就行。

require 'date'   # 提供Date和DateTime類
require 'time'   # 提供Time類(可直接使用,但導(dǎo)入后有更多方法)

一般來說,操作日期時(shí)間的常用操作包括:

  • 創(chuàng)建(構(gòu)建)日期、時(shí)間對(duì)象
  • 在字符串和日期時(shí)間對(duì)象之間進(jìn)行轉(zhuǎn)換
  • 日期時(shí)間的比較
  • 日期時(shí)間的運(yùn)算
  • 操作時(shí)區(qū)
  • 等等…

而這3個(gè)類中,都各自提供了一些方法,很多方法是重疊的。據(jù)我個(gè)人測(cè)試,DateTime這個(gè)標(biāo)準(zhǔn)庫(kù)效率是最高的。

下面,針對(duì)各種常見功能將這3個(gè)類結(jié)合在一起去介紹。

Ruby構(gòu)建日期時(shí)間對(duì)象

這3個(gè)類都能直接構(gòu)造日期、時(shí)間對(duì)象。其中Date只能構(gòu)造日期不能構(gòu)造時(shí)間對(duì)象。

Date構(gòu)造日期對(duì)象

Date構(gòu)造日期對(duì)象。如果提供了時(shí)間部分,則忽略時(shí)間部分。因?yàn)椴簧婕皶r(shí)間部分,所以不能也沒必要指定時(shí)區(qū)。

Ruby

# 1.構(gòu)造當(dāng)前日期對(duì)象:Date.today
>> Date.today
=> #<Date: 2019-08-05 ((2458701j,0s,0n),+0s,2299161j)>

>> puts Date.today
2019-08-05

# 2.構(gòu)造指定日期:Date.new
## 可以構(gòu)造超出2038年的日期
## 如果沒有給定月、日,則默認(rèn)為1
## 如果沒有提供任何參數(shù),默認(rèn)是-4712年1月1日,這沒什么意義
## 如果給定時(shí)間部分,則報(bào)錯(cuò)
>> Date.new(2018,3,20)
=> #<Date: 2018-03-20 ((2458198j,0s,0n),+0s,2299161j)>
>> Date.new(2078,3,20)
=> #<Date: 2078-03-20 ((2480113j,0s,0n),+0s,2299161j)>
>> Date.new(1900)
=> #<Date: 1900-01-01 ((2415021j,0s,0n),+0s,2299161j)>
>> Date.new
=> #<Date: -4712-01-01 ((0j,0s,0n),+0s,2299161j)>

# 3.構(gòu)造指定日期:Date.parse
## 根據(jù)字符串解析成日期格式
## 如果給定時(shí)間部分,則忽略
## 對(duì)于年份,可以給定1、2位數(shù)的和4位數(shù)的
## 對(duì)于1、2位數(shù),如果數(shù)值是大于等于69的,則默認(rèn)加上1900
## 對(duì)于0和68之間的數(shù)值,則默認(rèn)加上2000
>> Date.parse('2007/09/12')
=> #<Date: 2007-09-12 ((2454356j,0s,0n),+0s,2299161j)>
>> Date.parse('2007/9/12')
=> #<Date: 2007-09-12 ((2454356j,0s,0n),+0s,2299161j)>
>> Date.parse('2007-9-12')
=> #<Date: 2007-09-12 ((2454356j,0s,0n),+0s,2299161j)>
>> Date.parse('2007-9-12 12:30:59')
=> #<Date: 2007-09-12 ((2454356j,0s,0n),+0s,2299161j)>

>> Date.parse('08-9-12')
=> #<Date: 2008-09-12 ((2454722j,0s,0n),+0s,2299161j)>
>> Date.parse('68-9-12')
=> #<Date: 2068-09-12 ((2476637j,0s,0n),+0s,2299161j)>
>> Date.parse('69-9-12')
=> #<Date: 1969-09-12 ((2440477j,0s,0n),+0s,2299161j)>

# 4.使用strptime方法根據(jù)給定格式的字符串轉(zhuǎn)換成日期時(shí)間對(duì)象
## 關(guān)于支持的格式,參見后文
>> Date.strptime('2001-02-03', '%Y-%m-%d')
=> #<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>
>> Date.strptime('02-03-2001', '%m-%d-%Y')
=> #<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>

Time構(gòu)造日期時(shí)間對(duì)象

常見的方法是:new(別名now)、at、local(別名mktime)、parse。

注:Time類沒有strptime方法將給定格式的字符串轉(zhuǎn)換成日期時(shí)間對(duì)象。

# 1.new()或now()構(gòu)建當(dāng)前日期時(shí)間對(duì)象
## new也可以根據(jù)給定參數(shù)構(gòu)建日期時(shí)間對(duì)象,無參時(shí)等價(jià)于now
## 可以指定時(shí)區(qū)
>> Time.now
=> 2019-08-05 14:12:30 +0800
>> Time.new
=> 2019-08-05 14:12:31 +0800
>> Time.new(2007,11,6,17,10,0, "+08:00")  # 指定時(shí)區(qū)
=> 2007-11-06 17:10:00 +0800

# 2.at()將epoch轉(zhuǎn)換成日期時(shí)間對(duì)象
## 支持時(shí)區(qū),支持小數(shù)秒、毫秒、微秒、納秒
>> Time.at(1553488199)
=> 2019-03-25 12:29:59 +0800
>> Time.at(1553488199, in: '+08:00') # 指定時(shí)區(qū)
=> 2019-03-25 12:29:59 +0800
>> Time.at(1553488199.3).usec  # 小數(shù)秒0.3秒,即3毫秒
=> 299999
>> Time.at(1553488199,123.345,:millisecond).usec # 毫秒?yún)?shù)
=> 123344
>> Time.at(1553488199,123.345).nsec   # 微秒?yún)?shù)
=> 123344
>> Time.at(1553488199,123.345,:usec).nsec   # 微秒?yún)?shù)
=> 123344
>> Time.at(1553488199,123,:nsec).nsec # 納秒?yún)?shù)
=> 123

# 3.mktime或local根據(jù)參數(shù)構(gòu)建本地時(shí)區(qū)的日期時(shí)間對(duì)象
## 要構(gòu)建UTC時(shí)區(qū)時(shí)間,使用gm()或別名方法utc()
## mktime/local和gm/utc之間,除時(shí)區(qū)不同外,其它等價(jià)
>> Time.mktime(2009,10,23,14,3,6)
=> 2009-10-23 14:03:06 +0800
>> Time.mktime(2009,10,23)
=> 2009-10-23 00:00:00 +0800
>> Time.mktime(2009,10)
=> 2009-10-01 00:00:00 +0800

# 4.parse根據(jù)字符串轉(zhuǎn)換成日期時(shí)間對(duì)象,同樣可以指定時(shí)區(qū)
>> Time.parse("2009/12/25 12:29:59")
=> 2009-12-25 12:29:59 +0800
>> Time.parse("2009/12/25")
=> 2009-12-25 00:00:00 +0800
>> Time.parse("2009/12")
=> 2009-12-01 00:00:00 +0800
>> Time.parse("2009/12/25 12:29:59 +00:00") # 指定時(shí)區(qū)
=> 2009-12-25 12:29:59 +0000
>> Time.parse('2009-07-12 16:32:40.00123').nsec # 指定小數(shù)秒
=> 1230000

由于上面介紹的幾種Time類方法構(gòu)建出來的日期時(shí)間對(duì)象的時(shí)區(qū)默認(rèn)是+08:00(東八區(qū),中國(guó)所在時(shí)區(qū)即東八),所以指定時(shí)區(qū)與否可隨意。

但下面DateTime類的幾種方法構(gòu)造日期時(shí)間對(duì)象的時(shí)區(qū)默認(rèn)是+00:00,所以通常要指定時(shí)區(qū)。

DateTime構(gòu)造日期時(shí)間對(duì)象

DateTime是Date的子集,且由于某些方法被重寫,所以某些方法參數(shù)有一點(diǎn)點(diǎn)不同。最常使用的構(gòu)造器是new、now、parse和strptime。

另外,DateTime對(duì)象是包含納秒的。

# 1.new()方法構(gòu)造DateTime對(duì)象
## 可以指定時(shí)區(qū)、指定小數(shù)秒
>> DateTime.new(2009,1,2,3,4,5)
=> #<DateTime: 2009-01-02T03:04:05+00:00 ((2454834j,11045s,0n),+0s,2299161j)>
>> DateTime.new(2009,1,2,3,4,5,'+7') # 指定時(shí)區(qū)
=> #<DateTime: 2009-01-02T03:04:05+07:00 ((2454833j,72245s,0n),+25200s,2299161j)>
>> DateTime.new(2009,1,2,3,4,5,'+08:00')
=> #<DateTime: 2009-01-02T03:04:05+08:00 ((2454833j,68645s,0n),+28800s,2299161j)>
>> DateTime.new(2009,1,2,3,4,5.3,'+08:00') # 指定小數(shù)秒,即毫秒
=> #<DateTime: 2009-01-02T03:04:05+08:00 ((2454833j,68645s,300000000n),+28800s,2299161j)>
>> DateTime.new(2009,1,2,3,4,5.3,'+08:00').sec_fraction
=> (3/10)

# 2.now()獲取當(dāng)前時(shí)間:
>> DateTime.now
=> #<DateTime: 2019-08-05T15:00:42+08:00 ((2458701j,25242s,407854800n),+28800s,2299161j)>

# 3.parse解析字符串為日期時(shí)間對(duì)象
>> DateTime.parse('2009-12-20 12:03:30')
=> #<DateTime: 2009-12-20T12:03:30+00:00 ((2455186j,43410s,0n),+0s,2299161j)>
>> DateTime.parse('2009-12-20 12:03:30 +8')
=> #<DateTime: 2009-12-20T12:03:30+08:00 ((2455186j,14610s,0n),+28800s,2299161j)>

# 4.strptime解析給定格式的字符串為日期時(shí)間對(duì)象
## 關(guān)于支持的格式,參見后文
>> DateTime.strptime('2009-12-20 12:03:30 +8','%Y-%m-%d %H:%M:%S %z')
=> #<DateTime: 2009-12-20T12:03:30+08:00 ((2455186j,14610s,0n),+28800s,2299161j)>

期、時(shí)間有效性檢測(cè)

構(gòu)建日期時(shí)間對(duì)象時(shí),有些日期、時(shí)間是無效的,但因?yàn)槿≈捣秶牟煌?、特殊日期特殊時(shí)間點(diǎn)的取值不同,導(dǎo)致處理比較麻煩。

比如,每月可能有29、30、31天,但11月31號(hào)是無效的。再比如,秒數(shù)的范圍是在0-60,但第61秒僅作為閏秒時(shí)才是有效值,所以幾乎所有時(shí)間的第61秒都是錯(cuò)誤的秒數(shù)。

Time可以檢測(cè)范圍外的無效時(shí)間,但是不能檢測(cè)范圍內(nèi)的無效時(shí)間。比如Time知道11月32號(hào)是錯(cuò)誤的,但它不知道11月31號(hào)是錯(cuò)誤的,實(shí)際上Time會(huì)將有效范圍內(nèi)超出的部分進(jìn)位,比如11月31號(hào)進(jìn)位到12月1號(hào)。

# 有效日期
>> Time.new(2007,11,30,17,10,30)
=> 2007-11-30 17:10:30 +0800

# 范圍內(nèi)的無效日期,進(jìn)位到12月1號(hào)
>> Time.new(2007,11,31,17,10,30)
=> 2007-12-01 17:10:30 +0800

# 有效秒
>> Time.new(2007,11,31,17,10,59)
=> 2007-12-01 17:10:59 +0800

# 第61秒進(jìn)位到下一分鐘
>> Time.new(2007,11,31,17,10,60)
=> 2007-12-01 17:11:00 +0800

# 錯(cuò)誤的秒,報(bào)錯(cuò)
>> Time.new(2007,11,31,17,10,61)
ArgumentError: sec out of range
from (pry):25:in `initialize'

# 錯(cuò)誤的日期,報(bào)錯(cuò)
>> Time.new(2007,11,32,17,10,59)
ArgumentError: argument out of range
from (pry):26:in `initialize'

Time會(huì)進(jìn)位的特性有時(shí)候是有益的,但不利于檢測(cè)。好在,Date、DateTime可以很好的檢測(cè)無效的日期、時(shí)間,只要是無效的日期時(shí)間,它們都會(huì)報(bào)錯(cuò),其中Date只能檢測(cè)無效日期,DateTime可檢測(cè)無效日期,也能檢測(cè)無效時(shí)間。

# Date檢測(cè)無效日期
>> Date.new(2007,11,30)
=> #<Date: 2007-11-30 ((2454435j,0s,0n),+0s,2299161j)>
>> Date.new(2007,11,31)
ArgumentError: invalid date
from (pry):28:in `initialize'

# DateTime檢測(cè)無效日期、時(shí)間
>> DateTime.new(2007,11,31,11,12,13)
ArgumentError: invalid date
from (pry):31:in `new'
>> DateTime.new(2007,11,30,11,12,60)
ArgumentError: invalid date
from (pry):32:in `new'

既然它們會(huì)報(bào)錯(cuò),那么只要加上異常捕獲的代碼即可完成日期時(shí)間的有效性檢測(cè)。比如在Time類中使用DateTime類來檢測(cè)有效的日期和時(shí)間:

class Time
  def self.valid?(y,m=1,d=1,H=0,M=0,S=0,us=0)
    require 'date'
    begin
      dt = DateTime(y,m,d,H,M,S,us)
    rescue
      returin nil
    end
    dt
  end
end

ate、Time、DateTime對(duì)象之間的類型轉(zhuǎn)換

這三個(gè)類的淵源:

  • Time類是對(duì)底層C庫(kù)的時(shí)間函數(shù)的封裝,它們通常基于UNIX epoch,因此不能表示1970年以前的時(shí)間
  • Date類是對(duì)Time類的補(bǔ)充,用于處理1970年之前的時(shí)間,但是它只能處理日期不能處理時(shí)間
  • DateTime繼承自Date,可以處理任意時(shí)間點(diǎn)的日期時(shí)間,但有些Time的功能DateTime沒有

所有有些時(shí)候有必要對(duì)它們進(jìn)行類型的轉(zhuǎn)換。

這3個(gè)類都提供了下面3個(gè)方法,在各自之間進(jìn)行轉(zhuǎn)換:

to_date
to_time
to_datetime

例如:

# Date對(duì)象轉(zhuǎn)換
>> Date.today.to_date
=> #<Date: 2019-08-05 ((2458701j,0s,0n),+0s,2299161j)>
>> Date.today.to_time
=> 2019-08-05 00:00:00 +0800
>> Date.today.to_datetime
=> #<DateTime: 2019-08-05T00:00:00+00:00 ((2458701j,0s,0n),+0s,2299161j)>

# Time對(duì)象轉(zhuǎn)換
>> Time.now.to_date
>> Time.now.to_time
>> Time.now.to_datetime

# DateTime對(duì)象轉(zhuǎn)換
>> DateTime.now.to_date
>> DateTime.now.to_time
>> DateTime.now.to_datetime

需要注意,Date類對(duì)象由于不包含時(shí)間部分,它也沒有時(shí)區(qū)。所以:

  • Time/DateTime轉(zhuǎn)成Date后會(huì)丟失時(shí)間和時(shí)區(qū)部分的數(shù)據(jù)
  • Date對(duì)象to_time轉(zhuǎn)成Time對(duì)象,設(shè)置的時(shí)區(qū)是其默認(rèn)時(shí)區(qū)『+08:00』,而to_datetime轉(zhuǎn)成DateTime對(duì)象,設(shè)置的時(shí)區(qū)是其默認(rèn)時(shí)區(qū)『+00:00』。但是Time和DateTime之間的轉(zhuǎn)換不會(huì)變換時(shí)區(qū)
d = Date.new(2019,5,23)
d.to_time  #=> 2019-05-23 00:00:00 +0800
d.to_datetime.to_s #=> "2019-05-23T00:00:00+00:00"

日期時(shí)間和字符串、數(shù)值之間的轉(zhuǎn)換

這是常用的需求。

  • 日期時(shí)間到字符串:
    • to_s轉(zhuǎn)成特定的字符串格式
    • strftime轉(zhuǎn)成自定義的字符串格式,參見下文
  • 日期時(shí)間到數(shù)值:只有包含時(shí)間部分(即Date不在討論范圍)才能轉(zhuǎn)成數(shù)值
    • 通常轉(zhuǎn)成的是epoch時(shí)間,支持整數(shù)、浮點(diǎn)數(shù)、分?jǐn)?shù)
  • 字符串轉(zhuǎn)成日期時(shí)間:前文構(gòu)造日期時(shí)間對(duì)象部分已介紹
  • 數(shù)值轉(zhuǎn)日期時(shí)間:前文構(gòu)造日期時(shí)間對(duì)象部分已介紹

日期時(shí)間對(duì)象還支持轉(zhuǎn)換成數(shù)組。

先看Time類型對(duì)象,它支持to_s、to_f、to_i、to_r(轉(zhuǎn)分?jǐn)?shù))、to_a(轉(zhuǎn)數(shù)組)。

# 轉(zhuǎn)字符串
>> Time.now.to_s
=> "2019-08-05 15:29:49 +0800"

# 轉(zhuǎn)數(shù)值,即整數(shù)epoch,和Time.at是相反的功能
>> Time.now.to_i
=> 1564990192

# 轉(zhuǎn)浮點(diǎn)數(shù),即小數(shù)epoch
## 默認(rèn)保留6位小數(shù),即微秒級(jí)別
## 可以格式化保留成納秒級(jí)別的字符串
## 但無法轉(zhuǎn)成納秒級(jí)別的浮點(diǎn)數(shù),因?yàn)槌隽薴loat精度范圍
## 可以使用BigDecimal保存成科學(xué)記數(shù)法的浮點(diǎn)數(shù)
>> Time.now.to_f
=> 1564990197.671165  # 微秒
>> "%.9f" % Time.now.to_f
=> "1564990502.569714785"  # 納秒字符串
>> ("%.9f" % Time.now.to_f).to_f
=> 1564991500.1034229  # 超出,被剪掉

## 使用BigDecimal保存十進(jìn)制科學(xué)記數(shù)法浮點(diǎn)數(shù)
>> require 'bigdecimal'
>> BigDecimal("%.9f" % Time.now.to_f) # 納秒浮點(diǎn)數(shù)
=> 0.1564991123879058599e10

# 轉(zhuǎn)分?jǐn)?shù)
>> Time.now.to_r
=> (3912475500217301/2500000)

# 轉(zhuǎn)數(shù)組
## 10個(gè)數(shù)組元素
## [sec,min,hour,day,month,year,wday,yday,isdst,zone]
## [秒/分/時(shí)/日/月/年/周中天/年中天/是否夏令時(shí)/時(shí)區(qū)]
>> Time.now.to_a
=> [4, 30, 15, 5, 8, 2019, 1, 217, false, "DST"]

注意,Time所查看的時(shí)區(qū)以DST、CST、UTC、GMT這樣的方式顯示,而DateTime查看的時(shí)區(qū)則是以類似于『+08:00』這種方式顯示。

再看Date和DateTime轉(zhuǎn)這些類型。其實(shí)Date/DateTime支持的轉(zhuǎn)換方法很少,它們只支持to_s,其它方法都不支持。所以,要想轉(zhuǎn)成整數(shù),可以先to_time,再to_i。

>> Date.today.to_s
=> "2019-08-05"

>> Date.today.to_time
=> 2019-08-05 00:00:00 +0800
>> Date.today.to_time.to_i
=> 1564934400

>> DateTime.now.to_s
=> "2019-08-05T15:55:05+08:00"
>> DateTime.now.to_time.to_f
=> 1564991712.1981702

strftime方法

strptime是將給定格式的字符串轉(zhuǎn)成(解析成)日期時(shí)間對(duì)象,而strftime則是將日期時(shí)間轉(zhuǎn)成給定格式的字符串。

Date、Time和DateTime這3個(gè)類都具有strftime。

>> d = Date.today
>> d.strftime("%Y-%m-%d %H:%M:%S")
=> "2019-08-05 00:00:00"

>> dt = DateTime.now
>> dt.strftime("%Y-%m-%d %H:%M:%S")
=> "2019-08-05 16:00:03"

>> t = Time.now
>> t.strftime("%Y-%m-%d %H:%M:%S")
=> "2019-08-05 16:01:07"

其中百分號(hào)部分就是日期時(shí)間中的格式化字符串占位符。

另外,strftime和strptime所使用的格式是統(tǒng)一的。以下摘自官方手冊(cè):strftime

%<flags><width><modifier><conversion>
Flags:

-  don't pad a numerical output.
_  use spaces for padding.
0  use zeros for padding.
^  upcase the result string.
#  change case.
The minimum field width specifies the minimum width.

The modifiers are “E”, “O”, “:”, “::” and “:::”. “E” and “O” are ignored. No effect to result currently.

Format directives:

Date (Year, Month, Day):
  %Y - 4位整數(shù)年份,可以是負(fù)數(shù)
  %C - year / 100 (round down.  20 in 2009)
  %y - year % 100 (00..99)

  %m - 兩位數(shù)月份,不足時(shí)填充0(01..12)
          %_m  blank-padded ( 1..12)
          %-m  no-padded (1..12)
  %B - 英文名稱的月份全稱(January)
          %^B  大寫的月份全稱(JANUARY)
  %b - 簡(jiǎn)寫月份名稱(Jan)
          %^b  大寫的月份簡(jiǎn)寫(JAN)
  %h - 等價(jià)于%b

  %d - 兩位數(shù)月中天,不足時(shí)填充0(01..31)
          %-d  no-padded (1..31)
  %e - 月中天,空格填充不足位數(shù)( 1..31)

  %j - 年中天,0填充(001..366)

Time (Hour, Minute, Second, Subsecond):
  %H - 24-hour clock, zero-padded (00..23)
  %k - 24-hour clock, blank-padded ( 0..23)
  %I - 12-hour clock, zero-padded (01..12)
  %l - 12-hour clock, blank-padded ( 1..12)
  %P - lowercase(am or pm)
  %p - uppercase(AM or PM)

  %M - Minute of the hour (00..59)

  %S - Second of the minute (00..60)

  %L - 毫秒(000..999)
  %N - 小數(shù)秒,默認(rèn)是9位小數(shù),即納秒
      %3N  毫秒millisecond (3 digits)
      %6N  微秒microsecond (6 digits)
      %9N  納秒nanosecond  (9 digits)
      %12N 皮秒picosecond  (12 digits)
      %15N femtosecond (15 digits)
      %18N attosecond  (18 digits)
      %21N zeptosecond (21 digits)
      %24N yoctosecond (24 digits)

Time zone:
  %z - 時(shí)區(qū),從UTC開始偏移(例如:+0900)
      %:z - 時(shí)區(qū),從UTC開始偏移,但帶一個(gè)冒號(hào)(+09:00)
      %::z - 時(shí)區(qū),從UTC開始偏移,但帶兩個(gè)冒號(hào)(+09:00:00)
      %:::z - 時(shí)區(qū),從UTC開始偏移,冒號(hào)隨意(+09,+09:30,+09:30:30)
  %Z - 等價(jià)于%:z (+09:00)

Weekday:
  %A - 周幾的全稱(Sunday)
          %^A  大寫的周幾全稱(SUNDAY)
  %a - 周幾的簡(jiǎn)稱(Sun)
          %^a  大寫的周幾簡(jiǎn)稱(SUN)
  %u - 數(shù)值周幾(1..7),1表示周一(Monday is 1, 1..7)
  %w - 數(shù)值周幾(0..6),0表示周日(Sunday is 0, 0..6)

ISO 8601 week-based year and week number:
The week 1 of YYYY starts with a Monday and includes YYYY-01-04.
The days in the year before the first week are in the last week of
the previous year.
  %G - The week-based year
  %g - The last 2 digits of the week-based year (00..99)
  %V - Week number of the week-based year (01..53)

Week number:
The week 1 of YYYY starts with a Sunday or Monday (according to %U
or %W).  The days in the year before the first week are in week 0.
  %U - Week number of the year.  The week starts with Sunday.  (00..53)
  %W - Week number of the year.  The week starts with Monday.  (00..53)

Seconds since the Unix Epoch:
  %s - epoch秒,即從1970-01-01 00:00:00 UTC距離現(xiàn)在已經(jīng)過去的秒數(shù)
  %Q - 毫秒epoch

Literal string:
  %n - Newline character (\n)
  %t - Tab character (\t)
  %% - Literal ``%'' character

Combination: 其中%F和%T常用
  %c - date and time (%a %b %e %T %Y)
  %D - Date (%m/%d/%y)
  %F - The ISO 8601 date format (%Y-%m-%d)
  %v - VMS date (%e-%b-%Y)
  %x - Same as %D
  %X - Same as %T
  %r - 12-hour time (%I:%M:%S %p)
  %R - 24-hour time (%H:%M)
  %T - 24-hour time (%H:%M:%S)
  %+ - date(1) (%a %b %e %H:%M:%S %Z %Y)

查看日期時(shí)間各部分信息

比如查看一個(gè)日期中的年份、月份、分鐘、秒數(shù)、時(shí)區(qū)等信息。

對(duì)于Date和DateTime對(duì)象,提供了如下幾個(gè)查看各部分信息的方法:

  • year
  • month或mon
  • day
  • hour
  • minute或min
  • second或sec
  • sec_fraction或second_fraction:查看小數(shù)秒(結(jié)果以分?jǐn)?shù)顯示)
  • zone:查看時(shí)區(qū)
  • cweek:查看當(dāng)前星期是一年的第幾個(gè)星期(1-53)
  • yday:查看年中天(當(dāng)前日期在一年中的第幾天,1-366)
  • mday:查看月中天(1-31)
  • wday:查看周中天(一周中的第幾天,0-6,0代表周日,6代表周六)
  • day_fraction:查看一天以過去多少,以分?jǐn)?shù)表示,例如中午12點(diǎn)表示過去1/2,看下面示例
  • monday?:是周一嗎?
  • tuesday?:是周二嗎?
  • wednesday?:是周三嗎?
  • thursday?:是周四嗎?
  • friday?:是周五嗎?
  • saturday?:是周六嗎?
  • sunday?:是周日嗎?
  • leap?:是閏年嗎?

對(duì)于Time對(duì)象來說,除了上面幾個(gè)方法外(但不支持sec_fraction/second_fraction),它還支持直接查看毫秒、微妙、納秒,即將小數(shù)秒轉(zhuǎn)換成對(duì)應(yīng)的單位數(shù)值:

  • subsec:等價(jià)于sec_fraction/second_fraction,即以分?jǐn)?shù)的方式返回小數(shù)秒
  • usec:毫秒數(shù)
  • nsec:納秒數(shù)
# DateTime
>> dt = DateTime.new(2009,7,12,16,32,40.00123)
>> dt.year           #=> 2009
>> dt.mon            #=> 7
>> dt.day            #=> 12
>> dt.mday           #=> 12
>> dt.cweek          #=> 28
>> dt.hour           #=> 16
>> dt.min            #=> 32
>> dt.sec            #=> 40
>> dt.sec_fraction   #=> (123/100000)
>> dt.yday           #=> 193
>> dt.wday           #=> 0  周日
>> dt.sunday?        #=> true

# DateTime: day_fraction
>> DateTime.new(2009,7,12).day_fraction
=> (0/1)
>> DateTime.new(2009,7,12,12).day_fraction
=> (1/2)
>> DateTime.new(2009,7,12,16,32,40).day_fraction
=> (1489/2160)
>> DateTime.new(2009,7,12,23,59,59).day_fraction
=> (86399/86400)
>> DateTime.new(2009,7,12,16,32,40.00123).day_fraction
=> (5956000123/8640000000)

# Time
>> t = Time.parse('2009-07-12 16:32:40.00123')
>> t.year      #=> 2009
>> t.subsec    #=> (123/100000)
>> t.usec      #=> 1230
>> t.nsec      #=> 1230000

日期時(shí)間的運(yùn)算

這是比較常見的需求,比如加7天之后的日期,10天前的日期等等。不過,對(duì)于Ruby來說,這些都很簡(jiǎn)單,因?yàn)樗呀?jīng)實(shí)現(xiàn)好了相關(guān)的加減法運(yùn)算符以及一些相關(guān)的方法,非常方便。

日期時(shí)間加減法運(yùn)算

Date/DateTime/Time都實(shí)現(xiàn)了+ -操作,它們都返回新的日期時(shí)間對(duì)象:

  • 對(duì)于Time來說分別用于增加、減少秒數(shù)(可以是小數(shù))
  • 對(duì)于Date/DateTime來說分別用于增加、減少天數(shù)(可以是小數(shù))

下面是Date/DateTime類對(duì)象使用加減法進(jìn)行日期運(yùn)算的示例:

>> d = Date.parse('2019-02-26')
>> dt = DateTime.parse('2019-02-26 12:30:30')
>> d + 1
=> #<Date: 2019-02-27 ((2458542j,0s,0n),+0s,2299161j)>
>> d + 3
=> #<Date: 2019-03-01 ((2458544j,0s,0n),+0s,2299161j)>
>> d + 3 - 3
=> #<Date: 2019-02-26 ((2458541j,0s,0n),+0s,2299161j)>

>> (dt + 3).to_s
=> "2019-03-01T12:30:30+00:00"
>> (dt + 2.5).to_s
=> "2019-03-01T00:30:30+00:00"

下面是Time類對(duì)象使用加減法進(jìn)行時(shí)間運(yùn)算的示例,注意秒運(yùn)算可以是小數(shù):

>> t = Time.new(2019,2,26,12,30,30)
=> 2019-02-26 12:30:30 +0800
>> t + 20         #=> 2019-02-26 12:30:50 +0800
>> t + 86400      #=> 2019-02-27 12:30:30 +0800
>> t + 86400 * 3  #=> 2019-03-01 12:30:30 +0800
>> (t + 10.32).nsec  #=> 320000000

月份運(yùn)算

對(duì)于Date/DateTime類來說,還提供了月份運(yùn)算的功能<< >>

  • <<表示前幾個(gè)月,可以給負(fù)數(shù)來表示后幾個(gè)月
  • >>表示后幾個(gè)月,可以給負(fù)數(shù)來表示前幾個(gè)月
>> dt.to_s       # 2月26
=> "2019-02-26T12:30:30+00:00"

>> (dt << 1).to_s  # 1月26
=> "2019-01-26T12:30:30+00:00"
>> (dt >> -1).to_s
=> "2019-01-26T12:30:30+00:00"

>> (dt << -1).to_s  # 3月26
=> "2019-03-26T12:30:30+00:00"
>> (dt >> 1).to_s
=> "2019-03-26T12:30:30+00:00"

但是,月份操作需要注意,有些月份的最后一天值是不一樣的,比如3月份最后一天是31日,向前移1個(gè)月是2月,2月最后一天可能是28日,也可能是29日。而對(duì)于月份操作來說,當(dāng)運(yùn)算后的月份的天數(shù)超出了該月范圍時(shí),將自動(dòng)取該月最后一天。

>> d = Date.new(2019,3,31)

>> (d << 1).to_s
=> "2019-02-28"

這樣可能會(huì)導(dǎo)致一些意料之外的運(yùn)算結(jié)果。例如,3月31號(hào)前移兩個(gè)月本是1月31號(hào),但是通過兩次前移1個(gè)月,得到的將是1月28或1月29。

>> d = Date.new(2019,3,31)
>> (d << 2).to_s       #=> "2019-01-31"
>> (d << 1 << 1).to_s  #=> "2019-01-28"

>> (d << 1 << -1).to_s #=> "2019-03-28"

所以,使用<< >>來做月份運(yùn)算是不安全的,如果要保證安全,還是盡量使用日期時(shí)間的加減法進(jìn)行運(yùn)算。

日期時(shí)間的prev和next

除了+ - << >>這幾個(gè)運(yùn)算符,對(duì)于Date/DateTime來說還支持next/prev等一些操作:

  • next或succ
  • next_day
  • next_month
  • next_year
  • prev_day
  • prev_month
  • prev_year

當(dāng)然,這些都能通過前面介紹的+ - << >>來實(shí)現(xiàn)等價(jià)的。而且,對(duì)于month和year的操作,同樣有不安全的問題,參見上面對(duì)<< >>的介紹。

日期時(shí)間的比較

Date/Time/DateTime都實(shí)現(xiàn)了<=>運(yùn)算符,而且它們都mix-in了Comparable,所以可以直接進(jìn)行大小比較,還可以使用between?這樣的方法來判斷某個(gè)時(shí)間點(diǎn)是否在時(shí)間范圍內(nèi)。這是非常實(shí)用方便的功能。

此外,Date實(shí)現(xiàn)了===運(yùn)算符,它等價(jià)于==,所以只要日期相同,就返回true,而DateTime是Date的子類,所以,也適用于DateTime對(duì)象,盡管它們的時(shí)間部分可能不一樣。所以,Date和DateTime對(duì)象之間可以互相比較,但它們都不能直接于Time對(duì)象進(jìn)行比較。

>> d1 = Date.new(2019,5,23)
>> d2 = Date.new(2019,5,24)
>> d1 < d2  #=> true

>> dt1 = DateTime.new(2019,5,23,12,30,30.123)
>> dt2 = DateTime.new(2019,5,23,12,30,30.234)
>> dt1 < dt2    #=> true
>> dt1 === dt2  #=> true,盡管時(shí)間不一樣,但結(jié)果true
>> d1 === dt1   #=> true

>> t1 = Time.new(2019,5,23,12,30,30.123)
>> t2 = Time.new(2019,5,23,12,30,30.234)
>> t1 === t2    #=> false
>> t1 == t2     #=> false
>> t1 < t2      #=> true

日期時(shí)間的迭代

Date/DateTime還支持downtoupto兩種方式的日期迭代(Time不支持),默認(rèn)每次迭代一天。

此外,還支持step迭代,它可以指定迭代時(shí)的步長(zhǎng)。

>> d.to_s      #=> "2019-03-31"
>> (d+7).to_s  #=> "2019-04-07"
>> d.upto(d + 7) {|date| puts date}
2019-03-31
2019-04-01
2019-04-02
2019-04-03
2019-04-04
2019-04-05
2019-04-06
2019-04-07

>> (d + 7).downto(d) {|date| puts date}
2019-04-07
2019-04-06
2019-04-05
2019-04-04
2019-04-03
2019-04-02
2019-04-01
2019-03-31

對(duì)于step來說:

step(limit[, step=1]) → enumerator
step(limit[, step=1]){|date| ...} → self

唯一需要注意的是,step語(yǔ)句塊返回的是原始對(duì)象,所以在語(yǔ)句塊中應(yīng)當(dāng)做出一些有意義的操作,并且不依賴于語(yǔ)句塊來構(gòu)建返回值。

簡(jiǎn)單的用法如下:

d = Date.new(2019, 5, 23)
d1 = Date.new(2019, 5, 28)
d.step(d1) { |date| puts date }
puts "-" * 20
d.step(d1, 2) { |date| puts date }

輸出結(jié)果:

2019-05-23
2019-05-24
2019-05-25
2019-05-26
2019-05-27
2019-05-28
--------------------
2019-05-23
2019-05-25
2019-05-27

幾種構(gòu)建日期時(shí)間對(duì)象的效率對(duì)比

Date/DateTime/Time這幾個(gè)類都有幾種構(gòu)建日期時(shí)間對(duì)象的方式,但不同的構(gòu)建方式,其性能肯定是有差別的。

下面測(cè)試這幾種方式構(gòu)建100W個(gè)日期時(shí)間對(duì)象,來對(duì)比下它們的性能。

此處先說明結(jié)論:

  • 根據(jù)測(cè)試結(jié)果,使用new方法構(gòu)建日期時(shí)間對(duì)象幾乎總是最佳選擇
  • 手動(dòng)指定時(shí)區(qū)的效率要比自動(dòng)設(shè)置時(shí)區(qū)差,但Time.new除外,Time.new指定時(shí)區(qū)后效率提高幾倍
  • parse方法的效率最差,而且差很多很多

Date類的幾種構(gòu)建方式

Date只能構(gòu)建日期對(duì)象,不包含時(shí)間,所以在某些場(chǎng)景下不太適合。

下面是構(gòu)建100W個(gè)日期對(duì)象幾種方式的效率對(duì)比,從結(jié)果中可以看出,Date.new效率是最高的,Date.parse是最差的。

## Date.new
$ time ruby -r'date' -e '1000000.times {|x| Date.new(2017,3,23)}'
real    0m0.410s
user    0m0.203s
sys     0m0.203s

## Date.parse
$ time ruby -r'date' -e '1000000.times {|x| Date.parse("2017-3-23")}'
real    0m2.604s
user    0m2.406s
sys     0m0.219s

## Date.strptime
$ time ruby -r'date' -e '1000000.times {|x| Date.strptime("2017-3-23","%Y-%m-%d")}'
real    0m0.790s
user    0m0.609s
sys     0m0.203s

Time類的幾種構(gòu)建方式

Time類構(gòu)建100W個(gè)日期時(shí)間對(duì)象的幾種方式效率對(duì)比。從結(jié)果中可看出:

  • Time.at構(gòu)建效率是最好的,但是它只能轉(zhuǎn)換epoch時(shí)間戳
  • 其它通用的幾種構(gòu)建方式,Time.new效率最佳,特別是手動(dòng)指定時(shí)區(qū)時(shí),幾乎能比肩Time.at
  • Time.parse效率是最差的,而且差很多
# Time類
## Time.new,不指定時(shí)區(qū)
$ time ruby -r'time' -e '1000000.times {|x| Time.new(2017,3,23,16,30,15)}'
real    0m2.546s
user    0m0.969s
sys     0m1.578s

## Time.new,指定時(shí)區(qū)
$ time ruby -r'time' -e '1000000.times {|x| Time.new(2017,3,23,16,30,15,"+08:00")}'
real    0m0.663s
user    0m0.453s
sys     0m0.219s

## Time.at,不指定時(shí)區(qū)
$ time ruby -e '1000000.times {|x| Time.at(1490257815)}'
real    0m0.358s
user    0m0.141s
sys     0m0.219s

## Time.at,指定時(shí)區(qū)
$ time ruby -e '1000000.times {|x| Time.at(1490257815,in: "+08:00")}'
real    0m0.941s
user    0m0.734s
sys     0m0.219s

## Time.parse,指定時(shí)區(qū)
$ time ruby -r'time' -e '1000000.times {|x| Time.parse("2017-03-23 16:30:15 +0800")}'
real    0m10.949s
user    0m10.422s
sys     0m0.531s

## Time.parse,不指定時(shí)區(qū)
$ time ruby -r'time' -e '1000000.times {|x| Time.parse("2017-03-23 16:30:15")}'
real    0m10.972s
user    0m8.953s
sys     0m1.984s

## Time.mktime,指定時(shí)區(qū)
$ time ruby -r'time' -e '1000000.times {|x| Time.mktime(2017,3,23,16,30,15,"+08:00")}'
real    0m2.575s
user    0m0.984s
sys     0m1.578s

## Time.mktime,不指定時(shí)區(qū)
$ time ruby -r'time' -e '1000000.times {|x| Time.mktime(2017,3,23,16,30,15)}'
real    0m2.490s
user    0m0.984s
sys     0m1.531s

DateTime類的幾種構(gòu)建方式

DateTime類構(gòu)建100W個(gè)日期時(shí)間對(duì)象的幾種方式效率對(duì)比。從結(jié)果中可看出:

  • DateTime.new構(gòu)建效率是最好的,指定時(shí)區(qū)與否幾乎無差別
  • DateTime.parse效率是最差的,而且差很多
## DateTime.new:不指定時(shí)區(qū)
$ time ruby -r'date' -e '1000000.times {|x| DateTime.new(2017,3,23,16,30,15)}'
real    0m0.409s
user    0m0.219s
sys     0m0.203s

## DateTime.new:指定時(shí)區(qū)
$ time ruby -r'date' -e '1000000.times {|x| DateTime.new(2017,3,23,16,30,15,"+08:00")}'
real    0m0.502s
user    0m0.328s
sys     0m0.188s

## DateTime.strptime:不指定時(shí)區(qū)
$ time ruby -r'date' -e '1000000.times {|x| DateTime.strptime("2017-3-23 16:30:15","%Y-%m-%d %H:%M:%S")}'
real    0m0.994s
user    0m0.797s
sys     0m0.219s

## DateTime.strptime:指定時(shí)區(qū)
$ time ruby -r'date' -e '1000000.times {|x| DateTime.strptime("2017-3-23 16:30:15 +08:00","%Y-%m-%d %H:%M:%S %z")}
'
real    0m1.838s
user    0m1.656s
sys     0m0.203s

## DateTime.parse:不指定時(shí)區(qū)
$ time ruby -r'date' -e '1000000.times {|x| DateTime.parse("2017-3-23 16:30:15")}'
real    0m6.206s
user    0m5.984s
sys     0m0.203s

## DateTime.parse:指定時(shí)區(qū)
$ time ruby -r'date' -e '1000000.times {|x| DateTime.parse("2017-3-23 16:30:15 +08:00")}'
real    0m6.944s
user    0m6.734s
sys     0m0.203s

更多關(guān)于Ruby日期時(shí)間比較,Ruby日期轉(zhuǎn)換Ruby時(shí)間日期處理方法請(qǐng)查看下面的相關(guān)鏈接

相關(guān)文章

最新評(píng)論