2014-06-23 34 views
8

Come posso ottenere le date di inizio e fine per l'ora legale utilizzando Noda Time? La funzione seguente assolve questo compito, ma è orribilmente ingombrante e richiede una soluzione più semplice.Ottenere l'ora legale Inizio e fine in NodaTime

/// <summary> 
/// Gets the start and end of daylight savings time in a given time zone 
/// </summary> 
/// <param name="tz">The time zone in question</param> 
/// <returns>A tuple indicating the start and end of DST</returns> 
/// <remarks>Assumes this zone has daylight savings time</remarks> 
private Tuple<LocalDateTime, LocalDateTime> GetZoneStartAndEnd(DateTimeZone tz) 
{ 
    int thisYear = TimeUtils.SystemLocalDateTime.Year; // Get the year of the current LocalDateTime 

    // Get January 1, midnight, of this year and next year. 
    var yearStart = new LocalDateTime(thisYear, 1, 1, 0, 0).InZoneLeniently(tz).ToInstant(); 
    var yearEnd = new LocalDateTime(thisYear + 1, 1, 1, 0, 0).InZoneLeniently(tz).ToInstant(); 

    // Get the intervals that we experience in this year 
    var intervals = tz.GetZoneIntervals(yearStart, yearEnd).ToArray(); 

    // Assuming we are in a US-like daylight savings scheme, 
    // we should see three intervals: 
    // 1. The interval that January 1st sits in 
    // 2. At some point, daylight savings will start. 
    // 3. At some point, daylight savings will stop. 
    if (intervals.Length == 1) 
     throw new Exception("This time zone does not use daylight savings time"); 
    if (intervals.Length != 3) 
     throw new Exception("The daylight savings scheme in this time zone is unexpected."); 

    return new Tuple<LocalDateTime,LocalDateTime>(intervals[1].IsoLocalStart, intervals[1].IsoLocalEnd); 
} 

risposta

6

Non c'è una singola funzione incorporata di cui sono a conoscenza, ma i dati sono tutti lì, quindi è possibile crearne uno proprio.

Sei sulla strada giusta con quello che hai mostrato, ma ci sono alcune cose da considerare:

  • Normalmente le persone sono interessate alla fine punti degli intervalli. Restituendo l'inizio e l'interruzione solo dell'intervallo centrale, è probabile che si ottengano valori diversi da quelli previsti. Ad esempio, se si utilizza uno dei fusi orari degli Stati Uniti, ad esempio "America/Los_Angeles", la funzione restituisce le transizioni come 3/9/2014 3:00:00 AM e 11/2/2014 2:00:00 AM, dove probabilmente ci si aspetta le 2:00 per entrambi.

  • I fusi orari a sud dell'equatore che utilizzano l'ora legale l'avviano verso la fine dell'anno e lo terminano all'inizio dell'anno successivo. Quindi a volte gli elementi nella tupla potrebbero essere invertiti rispetto a ciò che ti aspetti che siano.

  • Ci sono molti fusi orari che non usano l'ora legale, quindi lanciare un'eccezione non è l'idea migliore.

  • Ci sono almeno due fusi orari che attualmente hanno quattro transizioni in un singolo anno ("Africa/Casablanca" e "Africa/Cairo") - con una "interruzione" nei loro periodi di DST per il Ramadan. E occasionalmente, ci sono transizioni non correlate a DST, come ad esempio quando Samoa changed its standard offset in 2011, che le ha dato tre transizioni in un singolo anno.

Prendendo tutto questo in considerazione, sembrerebbe meglio per restituire un elenco di punti di transizione singoli, piuttosto che una tupla di coppie di transizioni.

Inoltre, questo è minore, ma sarebbe meglio non associare affatto il metodo all'orologio di sistema. L'anno può essere facilmente passato per parametro. Quindi è possibile utilizzare questo metodo per anni non correnti, se necessario.

public IEnumerable<LocalDateTime> GetDaylightSavingTransitions(DateTimeZone timeZone, int year) 
{ 
    var yearStart = new LocalDateTime(year, 1, 1, 0, 0).InZoneLeniently(timeZone).ToInstant(); 
    var yearEnd = new LocalDateTime(year + 1, 1, 1, 0, 0).InZoneLeniently(timeZone).ToInstant(); 
    var intervals = timeZone.GetZoneIntervals(yearStart, yearEnd); 

    return intervals.Select(x => x.IsoLocalEnd).Where(x => x.Year == year); 
} 

notare anche, alla fine, è importante per filtrare solo i valori che sono in corso perché gli intervalli può benissimo estendersi l'anno successivo, o andare avanti all'infinito.

+0

Questa sarebbe la base corretta per un metodo bool semplice IsDaylightSavings (DateTimeZone timeZone, Instant instant) o c'è un modo migliore? – davidkomer

+0

Cosa fa il tuo metodo? La documentazione di Noda Time non è facile da capire. Non capisco cosa sia 'IsoLocalEnd' e come possa essere usato per ottenere i tempi di transizione dell'ora legale. – Azimuth

+0

@Azimuth - Con i documenti, un 'ZoneInterval' *" rappresenta un intervallo di tempo per il quale si applica un particolare Offset, "* e il suo [' IsoLocalEnd'] (http://nodatime.org/1.3.x/api/ ? topic = html/P_NodaTime_TimeZones_ZoneInterval_IsoLocalEnd.htm) proprietà * "restituisce l'ora di inizio locale dell'intervallo, come' LocalDateTime' nel calendario ISO. Questo non include alcun salvataggio legale "*. Questi sono intervalli semiaperti, quindi questo ci dà l'ora locale in cui avviene la transizione. –