确定日期开始的时间 [英] Determining the time at which a date starts

查看:181
本文介绍了确定日期开始的时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我想创建一个每日策划师,我想把这一天分成15分钟。



容易,对吧?从午夜开始,...错误!在美国/圣保罗,由于夏令时更改,每年有一天从01:00开始。



给定时区和日期,如何找到时代一天开始的时间?



我的第一个想法是使用以下内容,但假设每一天都有23:59。这可能不如假设每一天都有一个午夜。

  perl -MDateTime -E'

DateTime-> new(year => 2013,month => 10,day => 20)
- > subtract(days => 1)
- > set(hour => 23,minute => 59)
- > set_time_zone(America / Sao_Paulo)
- > add(minutes => 1)
- > ; strftime(%H:%M);
'
01:00

有更强大或更直接的替代方法?

解决方案

[此功能现已从 DateTimeX ::开始 ]



这里是一个仅使用DT公开的解决方案方法:

  sub day_start {
my($ y,$ m,$ d,$ tz)= @_ ;

$ tz = DateTime :: TimeZone-> new(name => $ tz)
if!ref($ tz);

我的$ dt = DateTime-> new(year => $ y,month => $ m,day => $ d);
我的$ target_day =($ dt-> utc_rd_values)[0];
我的$ min_epoch = int($ dt-> epoch()/ 60) - 24 * 60;
my $ max_epoch = int($ dt-> epoch()/ 60)+ 24 * 60;
while($ max_epoch> $ min_epoch){
我的$ epoch =($ min_epoch + $ max_epoch)>> 1;
$ dt = DateTime-> from_epoch(epoch => $ epoch * 60,time_zone => $ tz);
if(($ dt-> local_rd_values)[0]< $ target_day){
$ min_epoch = $ epoch;
} else {
$ max_epoch = $ epoch;
}
}

返回DateTime-> from_epoch(epoch => $ max_epoch * 60,time_zone => $ tz);
}

由于大多数日期都有午夜,所以应该在顶部添加一个支票在不需要时绕过搜索。



假设:




  • 没有dt可以添加时间以获得具有较早日期的dt。

  • 在时区开始之前,日期开始时间不超过24 * 60 * 60秒。

  • 在时区开始后,24小时不得超过24 * 60 * 60秒。

  • 只发生在零秒的时间。 (优化)



测试:

  {
#没有午夜。
my $ tz = DateTime :: TimeZone-> new(name =>'America / Sao_Paulo');
我的$ dt = day_start(2013,10,20,$ tz);
print($ dt-> epoch,,$ dt-> iso8601,\\\
); #1382238000 2013-10-20T01:00:00
$ dt-> subtract(seconds => 1);
print($ dt-> epoch,,$ dt-> iso8601,\\\
); #1382237999 2013-10-19T23:59:59
}

{
#两个半夜。
my $ tz = DateTime :: TimeZone-> new(name =>'America / Havana');
我的$ dt = day_start(2013,11,3,$ tz);
print($ dt-> epoch,,$ dt-> iso8601,\\\
); #1383451200 2013-11-03T00:00:00
$ dt-> subtract(seconds => 1);
print($ dt-> epoch,,$ dt-> iso8601,\\\
); #1383451199 2013-11-02T23:59:59
}


Say I want to create a daily planner, and I want to divide the day into 15 minute chunks.

Easy, right? Just start at midnight, and... Wrong! In America/Sao_Paulo, one day each year starts at 01:00 because of Daylight Saving Time changes.

Given a time zone and a date, how does one find the epoch time at which the day starts?

My first thought was to use the following, but it assumes each day has a 23:59. That's probably no better of an assumption than assuming each day has a midnight.

perl -MDateTime -E'
   say
      DateTime->new( year => 2013, month => 10, day => 20 )
      ->subtract( days => 1 )
      ->set( hour => 23, minute => 59 )
      ->set_time_zone("America/Sao_Paulo")
      ->add( minutes => 1 )
      ->strftime("%H:%M");
'
01:00

Is there a more robust or more direct alternative?

解决方案

[This functionality is now available from DateTimeX::Start]

Here's a solution using only DT's public methods:

sub day_start {
   my ($y, $m, $d, $tz) = @_;

   $tz = DateTime::TimeZone->new( name => $tz )
      if !ref($tz);

   my $dt = DateTime->new( year => $y, month => $m, day => $d );
   my $target_day = ( $dt->utc_rd_values )[0];
   my $min_epoch = int($dt->epoch()/60) - 24*60;
   my $max_epoch = int($dt->epoch()/60) + 24*60;
   while ($max_epoch > $min_epoch) {
      my $epoch = ( $min_epoch + $max_epoch ) >> 1;
      $dt = DateTime->from_epoch( epoch => $epoch*60, time_zone => $tz );
      if (( $dt->local_rd_values )[0] < $target_day) {
         $min_epoch = $epoch;
      } else {
         $max_epoch = $epoch;
      }
   }

   return DateTime->from_epoch(epoch => $max_epoch*60, time_zone => $tz);
}

Since most dates do have a midnight, a check should be added at the top to bypass the search when it's not needed.

Assumptions:

  • There is no dt to which one can add time to obtain a dt with an earlier date.
  • In no time zone does a date starts more than 24*60*60 seconds before the date starts in UTC.
  • In no time zone does a date starts more than 24*60*60 seconds after the date starts in UTC.
  • Jumps in time zones only occur on times with zero seconds. (Optimization)

Test:

{
    # No midnight.
    my $tz = DateTime::TimeZone->new( name => 'America/Sao_Paulo' );
    my $dt = day_start(2013, 10, 20, $tz);
    print($dt->epoch, " ", $dt->iso8601, "\n");  # 1382238000 2013-10-20T01:00:00
    $dt->subtract( seconds => 1 );
    print($dt->epoch, " ", $dt->iso8601, "\n");  # 1382237999 2013-10-19T23:59:59
}

{
    # Two midnights.
    my $tz = DateTime::TimeZone->new( name => 'America/Havana' );
    my $dt = day_start(2013, 11, 3, $tz);
    print($dt->epoch, " ", $dt->iso8601, "\n");  # 1383451200 2013-11-03T00:00:00
    $dt->subtract( seconds => 1 );
    print($dt->epoch, " ", $dt->iso8601, "\n");  # 1383451199 2013-11-02T23:59:59
}

这篇关于确定日期开始的时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆