時間永遠是人生的一大問題,但在`Ruby的世界中,卻不是什麼問題。只要我們熟悉一些時間上的技巧,基本上都難不倒我們。
Time.now
與 Time.current
的區別是Ruby
中非常重要的概念:
Time.now
使用當前機器作業系統的時區Time.current
使用 Rails 中設定的時區 (ActiveSupport
的方法)接著,我們再來看下列例子來觀察不同電腦,因時區設定的不同,而導致的不同結果。
⭐️ 自己的電腦時區(Mac)
Time.now
#=> 電腦的時區
#=> 2019-11-05 10:44:09 +0800
Time.current
#=> Rails的時區
#=> Tue, 05 Nov 2019 18:44:16 CST +08:00
Time.parse("2019-11-04 16:20:23")
#=> 2019-11-04 16:20:23 +0800
Time.zone.parse("2019-11-04 16:20:23")
#=> Mon, 04 Nov 2019 16:20:23 CST +08:00
Time.zone.parse("2019-11-04 16:20:23").to_i
#=> 1572855623
Time.parse("2019-11-04 16:20:23").to_i
#=> 1572855623
⭐️ 測試站的時區
Time.now
#=> 電腦的時區
#=> 2019-11-05 10:44:09 +0000
Time.current
#=> Rails的時區
#=> Tue, 05 Nov 2019 18:44:16 CST +08:00
Time.parse("2019-11-04 16:20:23")
#=> 2019-11-04 16:20:23 +0000
Time.zone.parse("2019-11-04 16:20:23")
#=> Mon, 04 Nov 2019 16:20:23 CST +08:00
Time.parse("2019-11-04 16:20:23").to_i
#=> 1572884423
Time.zone.parse("2019-11-04 16:20:23").to_i
#=> 1572855623
不過雲端服務中,我們可以將電腦的時區設定自己想要的時區。譬如,我們就可以將測試站的時區設定+8:00
Datetime 是一種可以表現時間的類別,為Ruby
的方法
> DateTime.tomorrow
#=> Sat, 28 Aug 2021
> DateTime.now.tomorrow
#=> Sat, 28 Aug 2021 10:51:58 +0800
在Ruby
& Rails
中,有很多物件都可以拿來處理時間。我們必須知道哪些方法是哪種Object
,會比較方便使用。
由於ActiveSupport::TimeWithZone
是Rails
的庫,無法在irb
裡面執行,可以應證Time.current
使用的是Rails
中設定的時區,才會需要使用Rails
提供的物件。
DateTime.now.class
#=> DateTime
DateTime.new.class
#=> DateTime
DateTime.strptime("1571393643",'%s').class
#=> DateTime
Time.now.class
#=> Time
Time.new.class
#=> Time
Time.at(1571393643).class
#=> Time
Time.current.class
#=> ActiveSupport::TimeWithZone
1.day.from_now.class
#=> ActiveSupport::TimeWithZone
2.days.ago.class
#=> ActiveSupport::TimeWithZone
Time.zone.class
#=> ActiveSupport::TimeZone
互動式irb
內看不懂 Time.current
Time.current
# Traceback (most recent call last):
# NoMethodError (undefined method `current' for Time:Class)
Time.now
#=> 2021-09-07 09:29:53.888093 +0800
下列介紹時間戳轉換成時間物件的方法
# 時間戳轉 Datetime
DateTime.strptime("1571393643",'%s')
#=> Fri, 18 Oct 2019 10:14:03 +0000
# 時間戳轉 Time
Time.at(1571393643)
#=> 2019-10-18 18:14:03 +0800
# 時間戳轉 Time
Time.zone.at(1571393643)
#=> Fri, 18 Oct 2019 18:14:03 CST +08:00
# 時間戳轉 Time
Time.zone.at(1571393643).strftime("%Y-%m-%d %H:%M:%S")
#=> => "2019-10-18 18:14:03"
# 時間字串轉為時間戳
#=== *1000 為13碼
Time.zone.parse('2019.12.25 17:00:00').to_i*1000
Ruby
也有提供特別的方法轉換時間
Time.now.localtime("+05:30")
#=> 2019-11-06 07:17:41 +0530
Time.now.localtime("+05:30")
#=> 2019-11-06 07:17:46 +0530
Time.now.localtime("+00:30")
#=> 2019-11-06 02:17:54 +0030
Time.now.localtime("+00:00")
#=> 2019-11-06 01:47:58 +0000
Time.now.localtime("+08:00")
#=> 2019-11-06 09:48:08 +0800
下列方法指的是明天的同一個時間
Date.tomorrow
Date.current.tomorrow
Date.now.tomorrow
DateTime.now.tomorrow.to_date
Time.now.tomorrow.to_date
Date.current + 1
Ruby
提供的這些方法,可以使我們能夠輕鬆應付複雜的問題,譬如說要將某一筆資料的紅利點數設定結束時間為今年的最後一天,或者下年的同月月底結束的話,可以用以下的方法寫
# 該年最後一天
Date.today.end_of_year
# 該年最後一月
Date.today.end_of_month
# 某日隔天最開頭 (00:00)
DateTime.tomorrow.beginning_of_day
# 某日隔天最結尾時間 (23:59)
DateTime.tomorrow.end_of_day
# 從今天算起一年後的該月最後一天
1.year.from_now.end_of_month
幾天後
1.day.from_now # 一天後
2.days.from_now # 兩天後
3.days.from_now # 三天後
指定日期的幾天後
#======= start_time 可填入任意時間
1.day.from_now(start_time)
# 明天
1.day.from_now(Time.current)
#=> Wed, 08 Sep 2021 15:35:47 CST +08:00
# 昨天的明天
1.day.from_now(1.day.ago)
#=> Tue, 07 Sep 2021 15:33:17 CST +08:00
# 昨天的明天
1.day.from_now(DateTime.now.yesterday)
#=> Tue, 07 Sep 2021 15:33:28 +0800
strftime
跟正規表達式一樣,都是每次用的時候,都要重新查詢的用法,以下例舉自己常用的幾種方法。
# 下列兩者意思等同
Time.current.strftime("%Y-%m-%d %H:%M:%S") #=> "2021-09-06 22:49:05"
Time.current.strftime("%F %T") #=> "2021-09-06 22:49:05"
DateTime.now.strftime('%Q')
#=> "1630999913620"
DateTime.now.strftime("%FT%T.%5N")
#=> "2021-09-07T15:32:28.76346""
Time.current
#=> Tue, 07 Sep 2021 09:14:01 CST +08:00
Time.current.to_time
#=> 2021-09-07 09:14:03 +0800
DateTime.now.to_time
#=> 2021-09-07 09:15:00 +0800
'2019.12.18 11:10:00'.to_datetime
#=> Wed, 18 Dec 2019 11:10:00 +0000
首先我們先講send_time
回傳的第一值為boolean
,其中true
代表意義為立即,相對來說,false
代表的意義為排程。在這裡,回傳的第一個值並不是重點,重點是在回傳的第二個值。
下列為Tool
的使用情境:
推播時間
電商平台實作推播,必須要顧及顧客在合理的時間收到手機通知,要不然在半夜或清晨讓顧客收到的話,顧客會有不好的觀感,甚至有可能會想要刪除App
,因此9-17點為當下推播,其餘時間設定排程推播
物流取貨時間:
實作物流方面,我們也必須顧及店家營業時間,在營業時間以外我們沒有辦法讓物流進店取貨,因此我們必須將營業時間以外的時間排到其他天的營業時間,以供順豐物流取貨。11點到17點可以請物流到府取貨,當天11點以前的物流單排在11點,而當天17點以後的物流單則排在隔天的11點。
我們會在 Day11詳細的介紹類別方法的使用,這邊只會提到如何使用。
class Tool
class << self
# 推播時間: 9點到17點
def notification_sent_at
send_time(9, 17)
end
# 物流取貨時間: 11點到17點
def sf_sent_at
send_time(11, 17).last.strftime("%F %T")
end
def send_time(start_hour, end_hour)
zero_am = DateTime.now.beginning_of_day
started_at = DateTime.now.beginning_of_day.change(hour: start_hour)
ended_at = DateTime.now.beginning_of_day.change(hour: end_hour)
if Time.current.between?(zero_am, started_at)
[false, started_at]
elsif Time.current.between?(ended_at, DateTime.now.tomorrow.beginning_of_day)
[false, DateTime.now.tomorrow.beginning_of_day.change(hour: start_hour)]
else
[true, Time.current]
end
end
end
end
⭐️ 尋找指定開始和結束時間的訂單
Order.where(created_at: params[:startedAt]..params[:endedAt])
SELECT `orders`.* FROM `orders` WHERE `orders`.`created_at` >= '2021-08-19 03:10:25.041651' AND `orders`.`created_at` < '2021-08-20 03:10:25.042367' LIMIT 11
下列問題留給大家想,以下也是解時間問題時,工程師常常思考的問題。
Day2-Day7 主要介紹的內容為基本Ruby
使用
Day8-10 會介紹區塊Block