tab guidelines bar ios datetime swift nsdate nscalendar

guidelines - tab bar ios



¿Cómo puedo configurar un objeto NSDate a la medianoche? (7)

Tengo un objeto NSDate y quiero configurarlo en un tiempo arbitrario (por ejemplo, medianoche) para poder usar la función timeIntervalSince1970 para recuperar datos de manera consistente sin preocuparme por el momento en que se crea el objeto.

He intentado usar un NSCalendar y modificar sus componentes utilizando algunos métodos de Objective-C, como este:

let date: NSDate = NSDate() let cal: NSCalendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)! let components: NSDateComponents = cal.components(NSCalendarUnit./* a unit of time */CalendarUnit, fromDate: date) let newDate: NSDate = cal.dateFromComponents(components)

El problema con el método anterior es que solo puede establecer una unidad de tiempo ( /* a unit of time */ ), por lo que solo podría ser preciso uno de los siguientes:

  1. Día
  2. Mes
  3. Año
  4. Horas
  5. Minutos
  6. Segundos

¿Hay una manera de establecer horas, minutos y segundos al mismo tiempo y conservar la fecha (día / mes / año)?


En caso de que alguien esté buscando esto:

Usando SwiftDate puedes hacer esto:

Date().atTime(hour: 0, minute: 0, second: 0)


En mi opinión, la solución, que es más fácil de verificar, pero quizás no la más rápida, es usar cadenas.

func set( hours: Int, minutes: Int, seconds: Int, ofDate date: Date ) -> Date { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" let newDateString = "/(dateFormatter.string(from: date)) /(hours):/(minutes):/(seconds)" dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" return dateFormatter.date(from: newDateString) }


Este es un ejemplo de cómo lo haría, sin usar la función dateBySettingHour (para asegurarse de que su código aún sea compatible con dispositivos iOS 7):

NSDate* now = [NSDate date]; NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *dateComponents = [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:now]; NSDate* midnightLastNight = [gregorian dateFromComponents:dateComponents];

Puaj

Hay una razón por la que prefiero la codificación en C # ...

Alguien desea algún código legible ...?

DateTime midnightLastNight = DateTime.Today;

;-)


Sí.

No necesita jugar con los componentes del NSCalendar en absoluto; simplemente puede llamar al método dateBySettingHour y usar el parámetro ofDate con su fecha existente.

let date: NSDate = NSDate() let cal: NSCalendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)! let newDate: NSDate = cal.dateBySettingHour(0, minute: 0, second: 0, ofDate: date, options: NSCalendarOptions())!

Para Swift 3:

let date: Date = Date() let cal: Calendar = Calendar(identifier: .gregorian) let newDate: Date = cal.date(bySettingHour: 0, minute: 0, second: 0, of: date)!

Entonces, para obtener su tiempo desde 1970, simplemente puede hacer

let time: NSTimeInterval = newDate.timeIntervalSince1970

dateBySettingHour se introdujo en OS X Mavericks (10.9) y obtuvo soporte para iOS con iOS 8.

Declaración en NSCalendar.h :

/* This API returns a new NSDate object representing the date calculated by setting hour, minute, and second to a given time. If no such time exists, the next available time is returned (which could, for example, be in a different day than the nominal target date). The intent is to return a date on the same day as the original date argument. This may result in a date which is earlier than the given date, of course. */ - (NSDate *)dateBySettingHour:(NSInteger)h minute:(NSInteger)m second:(NSInteger)s ofDate:(NSDate *)date options:(NSCalendarOptions)opts NS_AVAILABLE(10_9, 8_0);


Tu declaración

El problema con el método anterior es que solo puede establecer una unidad de tiempo ...

no es correcto. NSCalendarUnit ajusta al protocolo RawOptionSetType que se hereda de BitwiseOperationsType . Esto significa que las opciones se pueden combinar en bits & con & y | .

En Swift 2 (Xcode 7) esto se cambió nuevamente para ser un OptionSetType que ofrece una interfaz similar a un conjunto, ver por ejemplo Error al combinar NSCalendarUnit con OR (pipe) en Swift 2.0 .

Por lo tanto lo siguiente compila y funciona en iOS 7 y iOS 8:

let date = NSDate() let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! // Swift 1.2: let components = cal.components(.CalendarUnitDay | .CalendarUnitMonth | .CalendarUnitYear, fromDate: date) // Swift 2: let components = cal.components([.Day , .Month, .Year ], fromDate: date) let newDate = cal.dateFromComponents(components)

(Tenga en cuenta que he omitido las anotaciones de tipo para las variables, el compilador Swift deduce el tipo automáticamente de la expresión en el lado derecho de las asignaciones).

La determinación del inicio del día dado (medianoche) también se puede hacer con el método rangeOfUnit() (iOS 7 y iOS 8):

let date = NSDate() let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! var newDate : NSDate? // Swift 1.2: cal.rangeOfUnit(.CalendarUnitDay, startDate: &newDate, interval: nil, forDate: date) // Swift 2: cal.rangeOfUnit(.Day, startDate: &newDate, interval: nil, forDate: date)

Si su destino de despliegue es iOS 8, entonces es aún más simple:

let date = NSDate() let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! let newDate = cal.startOfDayForDate(date)

Actualización para Swift 3 (Xcode 8):

let date = Date() let cal = Calendar(identifier: .gregorian) let newDate = cal.startOfDay(for: date)


Swift iOS 8 y superior : la gente tiende a olvidar que los objetos Calendar y DateFormatter tienen una zona horaria. Si no configura la zona horaria deseada y el valor predeterminado de la zona horaria no es correcto para usted, entonces las horas y los minutos resultantes podrían estar apagados.

Nota: en una aplicación real puedes optimizar este código un poco más.

Nota: cuando no se preocupa por las zonas horarias, los resultados podrían ser correctos en un dispositivo y malos en otro dispositivo solo debido a las diferentes configuraciones de la zona horaria.

Nota: ¡ Asegúrese de agregar un identificador de zona horaria existente! Este código no controla un nombre de zona horaria faltante o mal escrito.

func dateTodayZeroHour() -> Date { var cal = Calendar.current cal.timeZone = TimeZone(identifier: "Europe/Paris")! return cal.startOfDay(for: Date()) }

Incluso podrías extender el lenguaje. Si la zona horaria predeterminada es adecuada para usted, no la configure.

extension Date { var midnight: Date { var cal = Calendar.current cal.timeZone = TimeZone(identifier: "Europe/Paris")! return cal.startOfDay(for: self) } var midday: Date { var cal = Calendar.current cal.timeZone = TimeZone(identifier: "Europe/Paris")! return cal.date(byAdding: .hour, value: 12, to: self.midnight)! } }

Y úsalo así:

let formatter = DateFormatter() formatter.timeZone = TimeZone(identifier: "Europe/Paris") formatter.dateFormat = "yyyy/MM/dd HH:mm:ss" let midnight = Date().midnight let midnightString = formatter.string(from: midnight) let midday = Date().midday let middayString = formatter.string(from: midday) let wheneverMidnight = formatter.date(from: "2018/12/05 08:08:08")!.midnight let wheneverMidnightString = formatter.string(from: wheneverMidnight) print("dates: /(midnightString) /(middayString) /(wheneverMidnightString)")

Las conversiones de cadena y el DateFormatter son necesarios en nuestro caso para algún formato y para mover la zona horaria, ya que el objeto de fecha en sí no mantiene ni se preocupa por un valor de zona horaria.

¡Cuidado! ¡El valor resultante podría diferir debido a un desplazamiento de zona horaria en algún lugar de su cadena de cálculo!


func resetHourMinuteSecond(date: NSDate, hour: Int, minute: Int, second: Int) -> NSDate{ let nsdate = NSCalendar.currentCalendar().dateBySettingHour(hour, minute: minute, second: second, ofDate: date, options: NSCalendarOptions(rawValue: 0)) return nsdate! }