#ios #date #swift #nsdateformatter
#iOS #Дата #swift #nsdateformatter
Вопрос:
Я вижу много сообщений о «странном поведении» в календаре iOS, но этого, похоже, там нет, поэтому я добавлю это в кучу.
У меня есть класс, который, помимо прочего, вычисляет разницу между двумя датами и отображает их в виде периода месяцев, дней и лет.
Мне нужно вернуться и протестировать это в ObjC, но я не думаю, что это происходит там, поскольку это переписывание очень старого приложения, которое я написал несколько лет назад на C.
Итак, сегодня, 30 июня, я писал модульные тесты и заметил, что календарь выдал одинаковое количество для двух разных дат.
Если быть точным, в нем говорится, что с 30 декабря 2012 года по 30 июня 2014 года ровно 1 год и шесть месяцев.
Я также говорю, что с 31 декабря 2012 года по 30 июня 2014 года составляет 1 год и шесть месяцев. ТОЧНО. Это должно быть 1 год, пять месяцев и 30 дней (я полагаю).
В любом случае обе даты не должны создавать одинаковый временной интервал.
Вот код, который я использую. Я не вижу ничего, что я делаю неправильно. Есть какие-либо подсказки?
Кстати: по какой-либо причине этот код не будет работать на игровой площадке. Возможно, я прошу слишком многого от системы.
import Foundation
class Gonkulator
{
var years:Int
var months:Int
var days:Int
init ( inStartDate:NSDate, inNowDate:NSDate )
{
// The reason for all this wackiness, is we want to completely strip out the time element of each date. We want the days to be specified at noon.
var fromString:String = NSDateFormatter.localizedStringFromDate ( inStartDate, dateStyle: NSDateFormatterStyle.ShortStyle, timeStyle: NSDateFormatterStyle.NoStyle )
var toString:String = NSDateFormatter.localizedStringFromDate ( inNowDate, dateStyle: NSDateFormatterStyle.ShortStyle, timeStyle: NSDateFormatterStyle.NoStyle )
var dateFormatter = NSDateFormatter()
dateFormatter.timeStyle = .NoStyle
dateFormatter.dateStyle = .ShortStyle
// We have stripped out the time information, and each day is at noon.
var startDate:NSDate = dateFormatter.dateFromString ( fromString ).dateByAddingTimeInterval ( 43200 ) // Make it Noon, Numbah One.
var stopDate:NSDate = dateFormatter.dateFromString ( toString ).dateByAddingTimeInterval ( 43200 )
// Get the Gregorian calendar
let myCalendar: NSCalendar = NSCalendar ( calendarIdentifier:NSGregorianCalendar )
// Create our answer from the components of the result.
var components = myCalendar.components ( NSCalendarUnit.YearCalendarUnit | NSCalendarUnit.MonthCalendarUnit | NSCalendarUnit.DayCalendarUnit, fromDate: startDate, toDate: stopDate, options: nil )
self.years = components.year
self.months = components.month
self.days = components.day
// DEBUG DISPLAY
// fromString = NSDateFormatter.localizedStringFromDate ( startDate, dateStyle: NSDateFormatterStyle.ShortStyle, timeStyle: NSDateFormatterStyle.NoStyle )
// toString = NSDateFormatter.localizedStringFromDate ( stopDate, dateStyle: NSDateFormatterStyle.ShortStyle, timeStyle: NSDateFormatterStyle.NoStyle )
// println ( "Start Date: " fromString " -Years: (self.years), Months: (self.months), Days: (self.days)" )
// println ( "End Date: " toString )
}
}
var dateFormatter = NSDateFormatter()
dateFormatter.timeStyle = .NoStyle
dateFormatter.dateStyle = .ShortStyle
var startDate:NSDate = dateFormatter.dateFromString ( "12/30/12" ).dateByAddingTimeInterval ( 43200 ) // Make it Noon, Numbah One.
var stopDate:NSDate = dateFormatter.dateFromString ( "06/30/14" ).dateByAddingTimeInterval ( 43200 )
// First create an instance for December 30, 18 months ago
let test = Gonkulator ( inStartDate: startDate, inNowDate: stopDate )
var years = test.years // This will be 1
var months = test.months // This will be 6
var days = test.days // This will be 0
startDate = dateFormatter.dateFromString ( "12/31/12" ).dateByAddingTimeInterval ( 43200 )
// Next, create an instance for December 31
let test2 = Gonkulator ( inStartDate: startDate, inNowDate: stopDate )
years = test2.years // This will be 1
months = test2.months // This will be 6 #WhiskeyTangoFoxtrot
days = test2.days // This will be 0 #WhiskeyTangoFoxtrot
Первый вызов проверяется как: Один год и шесть месяцев
Второй экземпляр должен быть один год, пять месяцев и тридцать дней
Комментарии:
1. Ваша проблема в том, что вы считаете, что григорианский календарь должен быть логичным и единообразным. Например, сколько точно длится месяц?
2. Вы правы (мы все должны использовать календарь ацтеков и соблюдать жертвенные обряды в кардинальные даты).
3. Однако обратите внимание на ссылки, которые я только что добавил этим утром. Они дают ожидаемый результат. Я действительно представил это как проблему с радаром, но мне ДЕЙСТВИТЕЛЬНО не нравится обвинять ОС или инструменты (но на самом деле это довольно вероятно, поскольку многие из этих материалов все еще незрелые).
4. С конца месяца 1 до конца месяца 4 — 3 месяца. С 30-го числа месяца 1 по 30-е число месяца 4 также составляет 3 месяца. Мне это кажется логичным — лучшая логика, которую вы можете извлечь из бессмысленной ситуации. Для этого нет единого «правильного» ответа, поэтому нужно выбрать правило, которое кажется наименее произвольным, и придерживаться его, даже если в результате получится какая-то очевидная бессмыслица. Разные разработчики могут выбирать немного разные правила.
5. Проверьте dateFormatString, возможно, вы используете YY вместо yy, и это может вызвать некоторые проблемы.