2010-06-10 11 views
10

.Net ha la funzione ToShortTimeString() incorporata per DateTime che utilizza il formato CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern. Restituisce qualcosa di simile a en-US: "17:00". Per una cultura di 24 ore come DE-DE, restituirebbe "17:00".Ottieni solo l'ora del giorno da DateTime utilizzando il formato 12 o 24 ore come definito dalla cultura corrente

Quello che voglio è un modo per restituire solo l'ora (così "5 pm" e "17" nei casi precedenti) che funziona con ogni cultura. Qual è il modo migliore/più pulito per farlo?

Grazie!

+0

Alcune colture usano "H: mm" (8:11) mentre altri usano "HH: mm" (08:11). Vuoi mantenere lo zero iniziale o no? – Greg

+0

Hmm .. Mi accontenterò di entrambi.Ma dal momento che sto cercando di mantenere la stringa più corta possibile, preferirei nessuno zero iniziale. – InvisibleBacon

risposta

6
// displays "15" because my current culture is en-GB 
Console.WriteLine(DateTime.Now.ToHourString()); 

// displays "3 pm" 
Console.WriteLine(DateTime.Now.ToHourString(new CultureInfo("en-US"))); 

// displays "15" 
Console.WriteLine(DateTime.Now.ToHourString(new CultureInfo("de-DE"))); 

// ... 

public static class DateTimeExtensions 
{ 
    public static string ToHourString(this DateTime dt) 
    { 
     return dt.ToHourString(null); 
    } 

    public static string ToHourString(this DateTime dt, IFormatProvider provider) 
    { 
     DateTimeFormatInfo dtfi = DateTimeFormatInfo.GetInstance(provider); 

     string format = Regex.Replace(dtfi.ShortTimePattern, @"[^hHt\s]", ""); 
     format = Regex.Replace(format, @"\s+", " ").Trim(); 

     if (format.Length == 0) 
      return ""; 

     if (format.Length == 1) 
      format = '%' + format; 

     return dt.ToString(format, dtfi); 
    } 
} 
+0

+1, questo è molto pulito. Tieni presente, come è stato sottolineato, che viene generata una FormatException se "la lunghezza del formato è 1 e non è uno dei caratteri identificatori di formato definiti per DateTimeFormatInfo". Inoltre, forse elimina gli spazi di ripetizione. Inoltre (solo interrogando, non l'ho visto prima) hai bisogno del controllo nullo sul provider - dalla documentazione penso. GInstance restituisce CurrentInfo se il provider è nullo? – Rawling

+0

Questa è fondamentalmente la stessa soluzione suggerita da Rawling, ma usando Regex. C'è un buon modo per non garantire spazi ripetuti usando la regex? – InvisibleBacon

+0

@Rawling, @InvisibleBacon: corretto. Ora normalizza gli spazi bianchi ripetuti e gestisce il caso in cui 'format.Length' è 1. Ho rimosso anche il controllo nullo non necessario. – LukeH

0

è possibile utilizzare DateTime.ToString() e fornire il formato desiderato come argomento.

-1
 
var culture = CultureInfo.CurrentCulture; 
bool uses24HourClock = string.IsNullOrEmpty(culture.DateTimeFormat.AMDesignator); 

var dt = DateTime.Now; 
string formatString = uses24HourClock ? "HH" : "h tt"; 
Console.WriteLine(dt.ToString(formatString, culture)); 

modifica di Sam:

Ecco il codice per dimostrare questo non funziona.

var date = new DateTime(2010, 1, 1, 16, 0, 0); 

foreach (CultureInfo cultureInfo in CultureInfo.GetCultures(CultureTypes.InstalledWin32Cultures)) 
{ 
    bool amMethod = String.IsNullOrEmpty(cultureInfo.DateTimeFormat.AMDesignator); 
    bool formatMethod = cultureInfo.DateTimeFormat.ShortTimePattern.Contains("H"); 

    if (amMethod != formatMethod) 
    { 
     Console.WriteLine("**** {0} AM: {1} Format: {2} Designator: {3} Time: {4}", 
          cultureInfo.Name, 
          amMethod, 
          formatMethod, 
          cultureInfo.DateTimeFormat.AMDesignator, 
          date.ToString("t", cultureInfo.DateTimeFormat)); 
    } 
} 
+0

Questo non funziona in molte culture. Spesso AMDesignator è definito come "?????????" invece di essere nulli o vuoti in culture che usano 24 ore. Anche molte culture che usano 24 ore hanno ancora specificato AMDesignator. –

+0

Ah. Ho appena controllato una cultura e ho scoperto che AM/PM era vuoto. Ho appena pensato che fosse coerente su tutte le culture. – simendsjo

+0

Alcune culture sono ancora più bizzarre. Esempio: af-ZA non ha AMDesignator, ma ha un PMDesignator e ShortTimePattern di HH: mm tt ... – code4life

4

vorrei controllare per vedere se contiene CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern "h", "hh", "H", "HH", "t" o "tt", e in quale ordine, e poi costruisci la tua stringa di formato personalizzata tra quelle.

ad es.

  • it-IT: map "h: mm tt" a "h tt"
  • ja-JP: Mappa "H: mm" a "H"
  • it-IT: Mappa "HH: mm "a" HH "

Quindi utilizzare .ToString(), passando la stringa creata.

Codice di esempio - questo praticamente elimina tutto ciò che non è t, T, h, H e più spazi. Ma, come sottolineato di seguito, solo una stringa di "H" potrebbe fallire ...

string full = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern; 
string sh = String.Empty; 
for (int k = 0; k < full.Length; k++) 
{ 
    char i = full[k]; 
    if (i == 'h' || i == 'H' || i == 't' || i == 'T' || (i == ' ' && (sh.Length == 0 || sh[sh.Length - 1] != ' '))) 
    { 
     sh = sh + i; 
    } 
} 
if (sh.Length == 1) 
{ 
    sh = sh + ' '; 
    string rtnVal = DateTime.Now.ToString(sh); 
    return rtnVal.Substring(0, rtnVal.Length - 1); 
{ 
else 
{ 
    return DateTime.Now.ToString(sh); 
} 
+0

Il problema che sto incontrando è che DateTime.Now.ToString ("H") genera un'eccezione di formato e I non sono sicuro del perché – Greg

+0

Sì, ho appena preso in giro il codice e hai ragione: -/ – Rawling

+0

Sì, l'ho notato anche io. Molto strano. Ho trovato l'aggiunta di uno spazio per la correzione: DateTime.Now.ToString ("H") .TrimEnd (''). Ma è abbastanza brutto .. – InvisibleBacon

2

Utilizzare questa:

bool use2fHour = 
    CultureInfo 
     .CurrentCulture 
     .DateTimeFormat 
     .ShortTimePattern.Contains("H"); 
0

Ugh, non voleva essere interessato, ma ora sono! Ecco il codice che rispetta tutte le culture e rende i designatori AM/PM nella posizione corretta, oltre a riconoscere il formato 24 ore, il tutto a seconda della cultura.

Fondamentalmente, questo metodo di estensione statica è sovraccarico per prendere la cultura corrente (senza parametri) o una cultura specificata.

DateTime.Now.ToTimeString()
DateTime.Now.ToTimeString(someCultureInfo)

codice è inferiore, include programma di esempio:

public static class DateTimeStaticExtensions 
    { 
     private static int GetDesignatorIndex(CultureInfo info) 
     { 
      if (info.DateTimeFormat 
       .ShortTimePattern.StartsWith("tt")) 
      { 
       return 0; 
      } 
      else if (info.DateTimeFormat 
       .ShortTimePattern.EndsWith("tt")) 
      { 
       return 1; 
      } 
      else 
      { 
       return -1; 
      } 
     } 

     private static string GetFormattedString(int hour, 
      CultureInfo info) 
     { 
      string designator = (hour > 12 ? 
       info.DateTimeFormat.PMDesignator : 
       info.DateTimeFormat.AMDesignator); 

      if (designator != "") 
      { 
       switch (GetDesignatorIndex(info)) 
       { 
        case 0: 
         return string.Format("{0} {1}", 
          designator, 
          (hour > 12 ? 
           (hour - 12).ToString() : 
           hour.ToString())); 
        case 1: 
         return string.Format("{0} {1}", 
          (hour > 12 ? 
           (hour - 12).ToString() : 
           hour.ToString()), 
          designator); 
        default: 
         return hour.ToString(); 
       } 
      } 
      else 
      { 
       return hour.ToString(); 
      } 
     } 

     public static string ToTimeString(this DateTime target, 
      CultureInfo info) 
     { 
      return GetFormattedString(target.Hour, info); 
     } 

     public static string ToTimeString(this DateTime target) 
     { 
      return GetFormattedString(target.Hour, 
       CultureInfo.CurrentCulture); 
     } 
    } 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var dt = new DateTime(2010, 6, 10, 6, 0, 0, 0); 

      CultureInfo[] cultures = 
       CultureInfo.GetCultures(CultureTypes.SpecificCultures); 
      foreach (CultureInfo culture in cultures) 
      { 
       Console.WriteLine(
        "{0}: {1} ({2}, {3}) [Sample AM: {4}/Sample PM: {5}", 
        culture.Name, culture.DateTimeFormat.ShortTimePattern, 
        (culture.DateTimeFormat.AMDesignator == "" ? 
         "[No AM]": 
         culture.DateTimeFormat.AMDesignator), 
        (culture.DateTimeFormat.PMDesignator == "" ? 
         "[No PM]": 
         culture.DateTimeFormat.PMDesignator), 
        dt.ToTimeString(culture), // AM sample 
        dt.AddHours(12).ToTimeString(culture) // PM sample 
        ); 
      } 

      // pause program execution to review results... 
      Console.WriteLine("Press enter to exit"); 
      Console.ReadLine(); 
     } 
    } 
-1

Prova utilizzando la proprietà DateTime.Hour.

Problemi correlati