NSDate到time_t,其值代表本地TZ

时间:2017-11-05 19:53:58

标签: ios objective-c

  • 我需要将NSDate转换为time_t
  • NSDate包含UTC时间
  • time_t必须包含本地时区的值

重要的:

  • NSDate可以是同时具有日光偏移的日期。

首先,我做了:

NSInteger tzOffset = [[NSTimeZone systemTimeZone] secondsFromGMT];
NSDate *localDate = [inputDate dateByAddingTimeInterval:tzOffset];
int daylightOffset =  [[NSTimeZone localTimeZone] daylightSavingTimeOffset];
BOOL isDaylightSavingTimeForDate = 
        [[NSTimeZone localTimeZone] isDaylightSavingTimeForDate:inputDate];
if (!isDaylightSavingTimeForDate) {
    localDate = [localDate dateByAddingTimeInterval:-1*daylightOffset];
}
time_t localTime = (time_t) [localDate timeIntervalSince1970];

仅当DaylightOffset对系统有效时才有效。

时不起作用
  • [[NSTimeZone localTimeZone] daylightSavingTimeOffset]返回0;
  • isDaylightSavingTimeForDate:inputDate返回true

是否有更好的方法将NSDate转换为time_t,其值代表本地TZ

示例:

我住在太平洋标准时间。 2017年11月UTC = -8小时,2018年5月,UTC = -7小时

  • 2017年11月,我想展示2018年5月4日下午1:00。
  • 输入日期= 2018-05-04 20:00:00 UTC
  • 使用上面的代码,localDate变为2018-05-04 12:00:00 UTC,因为当前系统tzOffset = -8小时。

我想要的是localDate = 2018-05-04 13:00:00 UTC

2 个答案:

答案 0 :(得分:3)

  

我需要将NSDate转换为time_t

time_t time = (time_t)[date timeIntervalSince1970];

这就是答案。

  

NSDate包含UTC时间

NSDate从不包含任何类型的时区。 NSDate是自参考时间以来的绝对秒数。你所在的时区并不重要。如果你在地球上并不重要。您正在使用的日历,时钟或其他人类设备无关紧要。这是一个绝对的时间点,每个人都会同意(忽略相对论效应)。

  

time_t必须包含本地时区的值

time_t与NSDate相同。它永远没有时区。这是一个时代以来的几秒钟。如果您认为它有时区,或者希望它有时区,那么您使用的是错误的工具。

  

2017年11月,我想显示 2018年5月4日下午1:00。

(强调我的)如果你想要展示某些东西,你需要一个NSDateFormatter。您不希望更改特定事件与纪元的秒数​​,您只想以时区感知的方式对其进行描述。

如果您想在基于日历的日期进行计算,那么您需要NSDateComponents。它增加了诸如“小时”和“天”这样的东西。使用NSDate的唯一时间单位是第二个。

  
      
  • 输入日期= 2018-05-04 20:00:00 UTC
  •   
  • localDate = 2018-05-04 13:00:00 UTC
  •   

这没有意义。为什么要在“输入日期”之前7小时发生“localDate”?你说你想要以不同的方式展示东西,但这表明它们发生在不同的时间点。如果目标是以不同方式显示,那么NSDateFormatter将会这样做。只需设置时区。

如果目标是在事件发生时实际更改,则可以使用dateByAddingTimeInterval:添加或减去要调整的时间。但这与时区无关;它将它移动到宇宙历史中的另一个点。

在这种情况下你在使用time_t是什么?

在太平洋标准时间显示2018-05-04 20:00:00 UTC为“2018/05/04 1:00 PM”:

// Just creating the date. I assume you already have it, but this shows how to
// build one out of components.

NSDateComponents *comp = [NSDateComponents new];
comp.year = 2018;
comp.month = 5;
comp.day = 4;
comp.hour = 20;
comp.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];

NSCalendar *gregorian = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];

NSDate *date = [gregorian dateFromComponents:comp];

// Now format it
NSDateFormatter *form = [NSDateFormatter new];
form.timeZone = [NSTimeZone timeZoneWithName:@"PST"];
form.dateFormat = @"YYYY/MM/dd h:mm a";

NSString *string = [form stringFromDate:date]; // "2018/05/04 1:00 PM"

这就是说,您应该始终考虑是否使用本地化的日期格式化程序。它们并不总是适用,但它们会为您处理很多日期本地化问题。例如:

NSDateFormatter *form = [NSDateFormatter new];
form.timeZone = [NSTimeZone timeZoneWithName:@"PST"];
form.dateStyle = NSDateFormatterShortStyle;
form.timeStyle = NSDateFormatterShortStyle;

这将输出“5/4/18,下午1:00”

或使用本地化模板:

form.dateFormat = [NSDateFormatter dateFormatFromTemplate:@"YYYY/MM/dd h:mm a" options:0
                                                   locale:[NSLocale currentLocale]];

在美国,这将是“05/04/2018,下午1:00”,但在法国,它将是“04/05/2018à1:00 PM”。有时这很好,有时它不是你需要的,但知道它存在是很好的。

答案 1 :(得分:-1)

这就是我解决问题的方法。

int daylightOffsetSystem = [[NSTimeZone localTimeZone] daylightSavingTimeOffset];

int daylightOffsetForStartDate =  [[NSTimeZone localTimeZone] daylightSavingTimeOffsetForDate:startDate];
BOOL isDaylightSavingTimeForStartDate = [[NSTimeZone localTimeZone] isDaylightSavingTimeForDate:startDate];
if (isDaylightSavingTimeForStartDate) {
    if (daylightOffsetSystem == 0) {
        localStartDate = [localStartDate dateByAddingTimeInterval:daylightOffsetForStartDate];
    }
} else {
    localStartDate = [localStartDate dateByAddingTimeInterval:-1*daylightOffsetSystem];
}


NSInteger tzOffset = [[NSTimeZone systemTimeZone] secondsFromGMT];
localStartDate = [localStartDate dateByAddingTimeInterval:tzOffset];