28

I have a default time zone setup for the rails application. And an instance of the Date object.

How can I get make Date#beginning_of_day to return the beginning of the day in the specified time zone, but not my local timezone.

Is there any other method to get beginning of the day time in the specified timezone for the given date?

date = Date.new(2014,10,29)

zone = ActiveSupport::TimeZone.new('CET')
date.foo(zone) # should return "Wed, 29 Oct 2014 00:00:00 CET +01:00"

zone = ActiveSupport::TimeZone.new('UTC')
date.foo(zone) # should return "Wed, 29 Oct 2014 00:00:00 UTC +00:00"
lulalala
  • 17,572
  • 15
  • 110
  • 169
Bogdan Gusiev
  • 8,027
  • 16
  • 61
  • 81
  • 1
    Isn't the beginning of the day always 00:00 regardless of timezone? – Ant Mar 24 '11 at 12:35
  • 2
    It's always 00:00, but 00:00 is always different in different timezones. The result of #beginning_of_day is aware of timezone. And seems it picks local timezone rather than default: Time.zone. – Bogdan Gusiev Mar 24 '11 at 12:39
  • I tried a few things in this post thread, and it results in the wrong answer for timezones east of UTC. I'm gonna post an "answer", since a comment won't format code. – mcr Jan 30 '13 at 22:19
  • @BogdanGusiev I added some examples. Please tell me if it is not what you meant. – lulalala Oct 29 '14 at 06:57

9 Answers9

52
DateTime.now.in_time_zone(Time.zone).beginning_of_day
Peder
  • 2,739
  • 3
  • 31
  • 33
  • That is not the case, you can end up in another day. For instance you've got 11 PM, and somewhere at the east it is already 1 am of the following day – Nick Roz Sep 30 '22 at 14:57
22
time_zone = Time.zone # any time zone really
time_zone.local(date.year, date.month, date.day)

Problem is, Date.beginning_of_day does not honor Time.zone in ActiveSupport 2.3

Compare https://github.com/rails/rails/blob/v2.3.11/activesupport/lib/active_support/core_ext/date/calculations.rb#L64 (AS 2.3)

to https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/date/calculations.rb#L74 and https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/date/zones.rb#L7 (AS 3)

lulalala
  • 17,572
  • 15
  • 110
  • 169
Leonid Shevtsov
  • 14,024
  • 9
  • 51
  • 82
  • 3
    It does for me now in 4.1, both `Time.now.beginning_of_day` and `Date.today.beginning_of_day` return the correct time with my application timezone – Paul Odeon Jul 10 '14 at 20:08
  • I tried `date.localtime.beginning_of_day`, seems to pickup the local timezone – sujay Aug 24 '21 at 04:37
9

Date#beginning_of_day will always return 00:00.

But as I understand you want to know time in other time zone while in current time zone is beginning of the day.

So. Let's find out beginning of the day in your current place. Imagine it is Paris, France:

bd = DateTime.now.in_time_zone('Paris').beginning_of_day
# or just
bd = DateTime.now.in_time_zone(1).beginning_of_day
#=> Thu, 24 Mar 2011 00:00:00 WET +01:00

Now lets found out what time is in Moscow:

moscow_time = bd.in_time_zone("Moscow") # or in_time_zone(3)
#=> Thu, 24 Mar 2011 02:00:00 AST +03:00
london_time = bd.in_time_zone("London")
#=> Wed, 23 Mar 2011 23:00:00 GMT +00:00
kyiv_time = bd.in_time_zone("Kyiv")
#=> Thu, 24 Mar 2011 01:00:00 EET +02:00 

For different form now day:

# You even shouldn't call now, because it by default will be 00:00
date = DateTime(2011, 1, 3).in_time_zone("-10")
# or
date = DateTime.new(2011,1,3,0,0,0,"-10")
# and same way as above
moscow_time = date.in_time_zone("Moscow") # or in_time_zone(3)

and converting Date to DateTime

date = Date.new(2011,1,3).to_datetime.change(:offset => "EST")
fl00r
  • 82,987
  • 33
  • 217
  • 237
  • Is it possible to do this for custom date, not just today? – Bogdan Gusiev Mar 24 '11 at 13:02
  • yes of course, 3 January 2011: `bd = DateTime.new(2011, 1, 3).in_time_zone('Paris').beginning_of_day` and so on – fl00r Mar 24 '11 at 13:03
  • And now, I have an Date object... Unfortunately It is not DateTime. If I do #to_datetime - I get beginning_of in wrong timezone. – Bogdan Gusiev Mar 24 '11 at 13:05
  • Try it before post: >> date = Date.new(2011,1,3).to_datetime.in_time_zone("EST").beginning_of_day => Sun, 02 Jan 2011 00:00:00 EST -05:00 – Bogdan Gusiev Mar 24 '11 at 13:10
  • 1
    `Try it before post` sounds unfriendly, Bogdan – fl00r Mar 24 '11 at 13:19
  • `Date.new(2011,1,3,"EST").to_datetime.change(:offset => "EST")` – fl00r Mar 24 '11 at 13:25
  • 2
    I agree wioth @fl00r here @Bogdan... let's keep it civil, remember people are helping you out here. – Jesse Wolgamott Mar 24 '11 at 13:33
  • 1
    You mis-understood the question. The question is not, if it's 00:00 in time zone X, what time does it make it in time zone Y. The question is, when is the beginning of the day in time zone Y. (Expressed with a timezone, or in UTC). – mcr Jan 30 '13 at 21:41
5

Going off Peder's answer, here's what I did for the PST time zone:

DateTime.now.in_time_zone("Pacific Time (US & Canada)").beginning_of_day
Tim S
  • 5,023
  • 1
  • 34
  • 34
  • His answer is a bit misleading, [have a look](https://stackoverflow.com/questions/5419148/rails-get-beginning-of-day-in-time-zone#comment130504480_7495738), you can end up in with the wrong date, in case you would like to have a specific one – Nick Roz Sep 30 '22 at 14:59
2

I know this post is old, but what about:

Time.zone.parse("12am")
Jason Galuten
  • 1,042
  • 2
  • 11
  • 20
1
may2 = Date.new(2012,5,2)
midnight = Time.zone.local(may2.year,may2.month,may2.day).beginning_of_day

Wed, 02 May 2012 00:00:00 UTC +00:00

midnight = Time.zone.local(may2.year,may2.month,may2.day).in_time_zone("Moscow").beginning_of_day

=> Wed, 02 May 2012 00:00:00 MSK +04:00

midnight = Time.zone.local(may2.year,may2.month,may2.day).in_time_zone("Alaska").beginning_of_day

=> Tue, 01 May 2012 00:00:00 AKDT -08:00

NOTICE, it's the WRONG DAY.

What is needed is a way to construct a TimeWithZone in the correct timezone.

Time.zone="Alaska"
midnight = Time.zone.local(may2.year,may2.month,may2.day)

I really dislike this, because as far as I can see, I've just changed the system notion of what zone I'm in. The idea is to change my database searches to match the zone of the client... So, I have to save zone and restore it:

foo = Time.zone; Time.zone="Alaska"; midnight = Time.zone.local(may2.year,may2.month,may2.day); Time.zone = foo

It seems like I ought be able to call TimeWithZone.new(), but I didn't figure out how.

mcr
  • 4,615
  • 2
  • 31
  • 30
0
ActiveSupport::TimeZone['Europe/London'].parse('30.07.2013') # 2013-07-29 23:00:00 UTC 
ActiveSupport::TimeZone['Asia/Magadan'].parse('30.07.2013') # 2013-07-29 12:00:00 UTC
Dmitry Lihachev
  • 504
  • 6
  • 20
0

As Leonid Shevtsov mentioned, Date.beginning_of_day does not honor Time.zone in ActiveSupport 2.3

An alternative I used, if your stuck using Rails 4.0 or ActiveSupport 2.3, and you need to use a custom date:

date = Date.new(2014,10,29)
date.to_time.change(hour: 0, min: 0, sec: 0).in_time_zone  #.beginning_of_day
date.to_time.change(hour: 23, min: 59, sec: 59).in_time_zone #.end_of_day

Results:

2.0.0-p247 :001 > date = Date.new(2014,10,29)
 => Wed, 29 Oct 2014 

2.0.0-p247 :002 > date.to_time.change(hour: 0, min: 0, sec: 0)
 => 2014-10-29 00:00:00 -0500 

2.0.0-p247 :003 > date.to_time.change(hour: 0, min: 0, sec: 0).in_time_zone
 => Wed, 29 Oct 2014 05:00:00 UTC +00:00 

2.0.0-p247 :004 > date.to_time.change(hour: 23, min: 59, sec: 59)
 => 2014-10-29 23:59:59 -0500 

2.0.0-p247 :005 > date.to_time.change(hour: 23, min: 59, sec: 59).in_time_zone
 => Thu, 30 Oct 2014 04:59:59 UTC +00:00 

My original failed model scope using .beginning_of_day to .end_of_day failed to work:

scope :on_day, ->(date) { where( created_at: date.beginning_of_day..date.end_of_day ) }

And, this is what fixed it, since I could not upgrade to Rails 4.0

scope :on_day, ->(date) { where( created_at: date.to_time.change(hour: 0, min: 0, sec: 0).in_time_zone..date.to_time.change(hour: 23, min: 59, sec: 59).in_time_zone ) }
Eric Wanchic
  • 2,046
  • 1
  • 23
  • 26
0

Generate new date in a specific time zone

If you would like to get beginning of the day for a specific date (and you know the exact date), then you have to use:

Time.use_zone('London'){ Time.zone.local(2022, 1, 1) }
# => Sat, 01 Jan 2022 00:00:00.000000000 GMT +00:00

It respects seasonal time change:

Time.use_zone('London'){ Time.zone.local(2022, 6, 1) }
# => Wed, 01 Jun 2022 00:00:00.000000000 BST +01:00

Although it is already referred by accepted answer I'd like to add that personally I prefer block notation.

Convert existing and find out what the day it is in another time zone

If you would like to know what day that would be for a specific timestamp/epoch/date that you already have you need to convert your existing date to the proper time zone, which is already referred by Peder's and Tim's answers:

Time.current.in_time_zone('London').beginning_of_day

Be aware, when converting existing date you may end up in another day (1st became 2nd):

Time.use_zone('London'){ Time.zone.local(2022, 6, 1, 23, 0, 0) }.in_time_zone('Tokyo').beginning_of_day
# => Thu, 02 Jun 2022 00:00:00.000000000 JST +09:00

If you are going to convert time, then Time.now or Time.current is indifferent, but I prefer using Time.current as a rule:

Time.now
# => 2022-09-30 15:29:16 +0000

Time.current
=> Fri, 30 Sep 2022 16:29:36.006315710 BST +01:00
Nick Roz
  • 3,918
  • 2
  • 36
  • 57