2009-01-31 13 views
43

Devo ottenere un formato DateTime personalizzato incluso il designatore AM/PM, ma voglio che "AM" o "PM" sia in minuscolo senza rendendo il resto dei caratteri in minuscolo.Ottieni AM/PM per una data ora in minuscolo utilizzando solo un formato datetime

È possibile utilizzare un unico formato e senza utilizzare un'espressione regolare?

Ecco quello che ho in questo momento:

item.PostedOn.ToString("dddd, MMMM d, yyyy a\\t h:mmtt") 

Un esempio di output in questo momento sarebbe Sabato 31 gennaio 2009 alle 01:34

+0

Maggiori informazioni presso http://stackoverflow.com/questions/448634/how-to-format-a-datetime-like-oct-10-2008-1043am-cst-in-c – tvanfosson

risposta

57

Io personalmente formattare in due parti: la parte non-am/pm, e la parte AM/PM con ToLower:

string formatted = item.PostedOn.ToString("dddd, MMMM d, yyyy a\\t h:mm") + 
        item.PostedOn.ToString("tt").ToLower(); 

Un'altra opzione (che studieremo in un secondo) è per prendere il DateTimeFormatInfo corrente, creare una copia e impostare i designatori am/pm nella versione minuscola. Quindi utilizzare le informazioni sul formato per la normale formattazione. Vorresti memorizzare il DateTimeFormatInfo, ovviamente ...

EDIT: Nonostante il mio commento, ho comunque scritto il bit di caching. Probabilmente non sarà più veloce rispetto al codice di cui sopra (in quanto comporta una serratura e una consultazione dei dizionari), ma non rendere il codice chiamante più semplice:

string formatted = item.PostedOn.ToString("dddd, MMMM d, yyyy a\\t h:mmtt", 
              GetLowerCaseInfo()); 

Ecco un programma completo per dimostrare:

using System; 
using System.Collections.Generic; 
using System.Globalization; 

public class Test 
{ 
    static void Main() 
    { 
     Console.WriteLine(DateTime.Now.ToString("dddd, MMMM d, yyyy a\\t h:mmtt", 
               GetLowerCaseInfo()); 
    } 

    private static readonly Dictionary<DateTimeFormatInfo,DateTimeFormatInfo> cache = 
     new Dictionary<DateTimeFormatInfo,DateTimeFormatInfo>(); 

    private static object cacheLock = new object(); 

    public static DateTimeFormatInfo GetLowerCaseInfo() 
    { 
     DateTimeFormatInfo current = CultureInfo.CurrentCulture.DateTimeFormat; 
     lock (cacheLock) 
     { 
      DateTimeFormatInfo ret; 
      if (!cache.TryGetValue(current, out ret)) 
      { 
       ret = (DateTimeFormatInfo) current.Clone(); 
       ret.AMDesignator = ret.AMDesignator.ToLower(); 
       ret.PMDesignator = ret.PMDesignator.ToLower(); 
       cache[current] = ret; 
      } 
      return ret; 
     } 
    } 
} 
+0

Mi piace questo meglio di qualsiasi altro postato in quell'altra domanda ... grazie! –

+0

Il codice pubblicato o l'idea di un nuovo DateTimeFormatInfo? Se è il secondo, verrò con te un codice. Se è il primo, non mi preoccuperò :) DateTimeFormatInfo.Clone() è probabilmente la via da seguire. –

+0

Il primo: il secondo, pur incredibilmente fantastico, è un vero e proprio overkill in questo caso. –

1

EDIT: Jon esempio è molto meglio, anche se penso che il metodo di estensione sia ancora la strada da percorrere per non dover ripetere il codice ovunque. Ho rimosso il sostituto e sostituito il primo esempio di Jon nel metodo di estensione. Le mie app sono in genere app intranet e non devo preoccuparmi delle culture non statunitensi.

Aggiungi un metodo di estensione per farlo.

public static class DateTimeExtensions 
{ 
    public static string MyDateFormat(this DateTime dateTime) 
    { 
     return dateTime.ToString("dddd, MMMM d, yyyy a\\t h:mm") + 
       dateTime.ToString("tt").ToLower(); 
    } 
} 

... 

item.PostedOn.MyDateFormat(); 

EDIT: Altre idee su come farlo a How to format a DateTime like "Oct. 10, 2008 10:43am CST" in C#.

+0

maaaan questo è esattamente quello che speravo di evitare :( –

+0

Non funziona anche per le culture con un designatore AM/PM diverso da AM/PM –

+0

Ciò che Jon ha detto.E ha il potenziale per bork in un locale in cui AM è considerato come parte del nome del giorno (improbabile, ma ancora negativo da un POV corretto) .Meglio usare un formato separato per la parte am/pm, ToLower() e aggiungerlo – Mark

18

Si potrebbe dividere la stringa di formato in due parti, e quindi in minuscolo la/PM parte AM, in questo modo:

DateTime now = DateTime.Now; 
string nowString = now.ToString("dddd, MMMM d, yyyy a\\t h:mm"); 
nowString = nowString + now.ToString("tt").ToLower(); 

Tuttavia, credo che il più el soluzione egant è quella di utilizzare un DateTimeFormatInfo instance che si costruisce e sostituire le AMDesignator e PMDesignator proprietà con le "am" e "pm", rispettivamente:

DateTimeFormatInfo fi = new DateTimeFormatInfo(); 

fi.AMDesignator = "am"; 
fi.PMDesignator = "pm"; 

string nowString = now.ToString("dddd, MMMM d, yyyy a\\t h:mmtt", fi); 

È possibile utilizzare l'istanza DateTimeFormatInfo di personalizzare molti altri aspetti di trasformare un DateTime a a string.

+0

Preferisco questo approccio perché la variabile "now" non è disponibile per me: ho un'espressione DataBind complicata che apparirebbe brutta e che gestisce tutto in un'unica chiamata di funzione. – umbyersw

+1

Mi piace l'approccio DateTimeFormatInfo, soprattutto perché abbiamo alcuni casi in cui vorremmo visualizzare "a.m." e "p.m." (compresi i periodi), il che rende la soluzione ToLower() molto più caotica. – JackAce

+0

O semplicemente 'now.ToString (" dddd, MMMM d, yyyy a \\ t h: mmtt ", nuovo DateTimeFormatInfo {AMDesignator =" am ", PMDesignator =" pm "});' –

1

Il problema con gli approcci di cui sopra è che la ragione principale per cui si utilizza una stringa di formato è di abilitare la localizzazione e gli approcci dati finora si interrompono per qualsiasi paese o cultura che non desidera includere un finale o pm.Quindi quello che ho fatto è stato scritto un metodo di estensione che comprende una sequenza di formato aggiuntiva "TT" che indica un am/pm minuscolo. Il codice qui sotto è il debug per i miei casi, ma potrebbe non essere ancora perfetta:

/// <summary> 
    /// Converts the value of the current System.DateTime object to its equivalent string representation using the specified format. The format has extensions over C#s ordinary format string 
    /// </summary> 
    /// <param name="dt">this DateTime object</param> 
    /// <param name="formatex">A DateTime format string, with special new abilities, such as TT being a lowercase version of 'tt'</param> 
    /// <returns>A string representation of value of the current System.DateTime object as specified by format.</returns> 
    public static string ToStringEx(this DateTime dt, string formatex) 
    { 
     string ret; 
     if (!String.IsNullOrEmpty(formatex)) 
     { 
      ret = ""; 
      string[] formatParts = formatex.Split(new[] { "TT" }, StringSplitOptions.None); 
      for (int i = 0; i < formatParts.Length; i++) 
      { 
       if (i > 0) 
       { 
        //since 'TT' is being used as the seperator sequence, insert lowercase AM or PM as appropriate 
        ret += dt.ToString("tt").ToLower(); 
       } 
       string formatPart = formatParts[i]; 
       if (!String.IsNullOrEmpty(formatPart)) 
       { 
        ret += dt.ToString(formatPart); 
       } 
      } 
     } 
     else 
     { 
      ret = dt.ToString(formatex); 
     } 
     return ret; 
    } 
0

questo dovrebbe essere il più performante di tutte queste opzioni. Ma troppo male non potevano lavorare con l'opzione minuscola nel formato DateTime (tt opposto a TT?).

public static string AmPm(this DateTime dt, bool lower = true) 
    { 
     return dt.Hour < 12 
      ? (lower ? "am" : "AM") 
      : (lower ? "pm" : "PM"); 
    } 
Problemi correlati