2013-06-19 22 views
21

Ben tarih 2012/12/28 içeren LocalDate var ve hâli yerelleştirilmiş ay adı (Lehçe yani Aralık) ile yazdırmak istediğiniz Polonyalı hangi (grudnia ve grudzień sırasıyla) dan farklıdır. Ayrıca özel bir biçim kullanmak istiyoruz yarattığım benimkinin DateTimeFormatter kullanılarak DateTimeFormatterBuilder (AFAIK Joda-Time kendisine doğru yol olan):Ay adı Joda-Time DateTimeFormatter

private static final DateTimeFormatter CUSTOM_DATE_FORMATTER 
    = new DateTimeFormatterBuilder() 
     .appendLiteral("z dnia ") 
     .appendDayOfMonth(1) 
     .appendLiteral(' ') 
     .appendText(new MonthNameGenitive()) // <-- 
     .appendLiteral(' ') 
     .appendYear(4, 4) 
     .appendLiteral(" r.") 
     .toFormatter() 
     .withLocale(new Locale("pl", "PL")); // not used in this case apparently 

çıktı olmalı "z dnia 28 grudnia 2012 r. ".

Soruma soru bir okla işaretlenmiş satır hakkında: MonthNameGenitive nasıl uygulamalıyım? Şu anda DateTimeFieldType uzanır ve oldukça fazla kodu vardır: Ben pek çok sihirli yöntemleri uygulamak zorunda beri

final class MonthNameGenitive extends DateTimeFieldType { 
    private static final long serialVersionUID = 1L; 

    MonthNameGenitive() { 
    super("monthNameGenitive"); 
    } 

    @Override 
    public DurationFieldType getDurationType() { 
    return DurationFieldType.months(); 
    } 

    @Override 
    public DurationFieldType getRangeDurationType() { 
    return DurationFieldType.years(); 
    } 

    @Override 
    public DateTimeField getField(final Chronology chronology) { 
    return new MonthNameGenDateTimeField(chronology.monthOfYear()); 
    } 

    private static final class MonthNameGenDateTimeField 
     extends DelegatedDateTimeField { 
    private static final long serialVersionUID = 1L; 
    private static final ImmutableList<String> MONTH_NAMES = 
     ImmutableList.of(
      "stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", 
      "lipca", "sierpnia", "września", "października", "listopada", 
      "grudnia"); 

    private MonthNameGenDateTimeField(final DateTimeField field) { 
     super(field); 
    } 

    @Override 
    public String getAsText(final ReadablePartial partial, 
     final Locale locale) { 
     return MONTH_NAMES.get(
      partial.get(this.getType()) - 1); // months are 1-based 
    } 
    } 

} 

, özensiz ve bana değil kurşun geçirmez görünüyor artı (getAsText(ReadablePartial, Locale)) süre DelegatedDateTimeField kullanarak ve tek bir yöntemi geçersiz kılmasını ediyorum diğerleri de aynı isimde vardır:

  • getAsText(long, Locale)
  • getAsText(long)
  • getAsText(ReadablePartial, int, Locale)
  • getAsText(int, Locale)

istenen çıkışı (DateTimeFormatter kullanarak) veya doğru yaklaşımım almak için daha iyi bir yaklaşım henüz çok ayrıntılı var mı?

DÜZENLEME: (JSR-310 dayanan Joda benzer,) yeni JDK8 Zaman API ile aynı şeyi başarmak için denedim ve kolayca yapılabilir

:

private static final java.time.format.DateTimeFormatter JDK8_DATE_FORMATTER 
    = new java.time.format.DateTimeFormatterBuilder() 
     .appendLiteral("z dnia ") 
     .appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NORMAL) 
     .appendLiteral(' ') 
     .appendText(ChronoField.MONTH_OF_YEAR, MONTH_NAMES_GENITIVE) // <-- 
     .appendLiteral(' ') 
     .appendValue(ChronoField.YEAR, 4) 
     .appendLiteral(" r.") 
     .toFormatter() 
     .withLocale(new Locale("pl", "PL")); 

MONTH_NAMES_GENITIVE özel ay isimleriyle Map<Long, String> olup, kullanımı çok kolaydır. Bakınız DateTimeFormatterBuilder#appendText(TemporalField, Map). Bu değişiklik (benim kullanım örneği için doğru olmakla birlikte varsayılan olarak hâli içinde DateFormatSymbols.getInstance(new Locale("pl", "PL")).getMonths() döner ay isimler ... Lehçe, söylediğimiz çünkü

İlginç JDK8 içinde bütün bu Polonyalı aylık isim hâli oyun gerekli değildir "bugün, 28 Aralık 2012", "genitive olarak ay isimlerini kullanıyor"), diğer bazı durumlarda (“Aralık 2012'yi aday göstererek kullanıyoruz”) zor olabilir ve geriye dönük olarak uyumsuz olabilir.

+1

Aslında genitive kullanmak ve diğer (nominative?) Sürümünü ne zaman kullanmak için işe yaramıyor aslında biraz şaşırıyorum - biz kesinlikle Noda Time doğru elde etmeye çalışın. –

+1

@JonSkeet JDK8'de, orijinallik/nominative versiyonun ['TextStyle'] (http://download.java.net/jdk8/docs/api/java/time/format/TextStyle.html) enum sabitleriyle desteklendiği görülüyor. 'FULL' /' FULL_STANDALONE' '' FULL' varsayılan ve Lehçe için genitive ve 'FULL_STANDALONE' nominative - ayrıca bkz [yerelleştirilmiş isimlerle bu XML dosyası] (http://hg.openjdk.java.net/threeten/ threeten/jdk/dosya/73a95812438c/src/share/sınıfları/güneş/util/CLDR/kaynaklar/21_0_1/ortak/ana/pl.xml). Yani .appendText (ChronoField.MONTH_OF_YEAR, TextStyle.FULL_STANDALONE) 'standart ay adı için kullanılabilir. – Xaerxess

cevap

13

Sen benim sempati var - Joda Zamanda alan sistem biraz karmaşıktır. Bununla birlikte, bu durumda en basit yaklaşımın aslında DateTimeFormatterBuilder.append(DateTimePrinter printer)'u kullanmasını öneririm.Bu yaklaşımın yalnızca baskıyla ilgileniyorsanız, sadecenumaralınumaralı çalışmayı kapsayacağını unutmayın - eğer ayrıştırmak gerekirse, hayat daha da karmaşıklaşır. yalnızca tek bir kültürde sadece ilgilendiğiniz olarak Locale görmezden mutluyuz, özellikle nispeten basit olduğunu DateTimePrinter uygulamak gerekir Bu noktada

. Tek bir yöntemde tüm mantığı (çok fazla olamayacak) koyabilir ve yöntemlerin geri kalanını yalnızca bu yönteme delege edebilirsiniz. long ve DateTimeZone'u kullanan aşırı yüklenmeler için, DateTime'u oluşturun ve toLocalDateTime numaralı telefonu arayın; diğer noktada, diğer yöntemlere delege edebilirsiniz. Sonra kolayca görmezden somut bir alt sınıfı yazabilir

:

DÜZENLEME: Eğer sadece yerel değerlere önem bilseydi Aslında, seçeneklerden biri, bir soyut temel sınıf yazmak olacaktır Eğer hepsi tek sınıfta bu yapabileceğini tabii

public class PolishGenitiveMonthPrinter extends SimpleDateTimePrinter { 

    private static final ImmutableList<String> MONTH_NAMES = 
      ImmutableList.of(
       "stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", 
       "lipca", "sierpnia", "września", "października", "listopada", 
       "grudnia"); 

    private static final int MAX_MONTH_LENGTH; 

    static { 
     int max = 0; 
     for (String month : MONTH_NAMES) { 
      if (month.length() > max) { 
       max = month.length(); 
      } 
     } 
     MAX_MONTH_LENGTH = max; 
    } 

    @Override 
    public int estimatePrintedLength() { 
     return MAX_MONTH_LENGTH; 
    } 

    @Override 
    protected String getText(ReadablePartial partial, Locale locale) { 
     int month = partial.get(DateTimeFieldType.monthOfYear()); 
     return MONTH_NAMES.get(month - 1); 
    } 
} 

ama muhtemelen gelecekte taban sınıfı daha yeniden kullanılabilir hale getirmek için dışarı kırardım: yerel ve sadece ay döndürür.

+1

'DateTimePrinter' arayüzünü gördüm, ancak * internal * olarak belgelenmiş bir not var. * Uygulama kullanıcıları nadiren bunu kullanacak sınıf doğrudan * ve kamu uygulamaları yoktur, bu yüzden özel 'DateTimeFieldType 'yerine kullandım. Bununla birlikte, girişimin daha temiz ve daha az ayrıntılı olduğundan, kesinlikle kullanacağım. BTW Joda-Time çekirdeğinde neden "SimpleDateTimePrinter" bulunmadığını merak ediyorum, çünkü DateTimePrinter 'DateTimeFormatterBuilder' public API'sinde. – Xaerxess

+2

@Xaerxess: "İç" parçayı tespit etmemiştim - ama doğru bir şekilde uygulanması oldukça kolay görünüyor ve söylediğiniz gibi bir kamusal tip olarak görünüyor. Ben nadiren * normal uygulama kullanıcıları tarafından doğrudan kullanılacağını anlayabiliyorum - ama tabii ki bu bir * problem * olmasıyla aynı şey değildir :) –

+1

Haklısınız, muhtemelen bu * nadir kullanım * ;) 'DateTimeParser', Joda'nın DateTimeFormatterBuilder'sında görünen ve JSR-311'den (düzenlenmiş soruya bakınız) yenisini oluşturucu ile karşılaştırdıktan sonra, orada" iç "sınıfların bulunduğundan şüpheleniyorum. biçimlendirme API'sı bu sorudan bazı gelişmiş şeylere izin vermedi. Java 8 Time API bu sorunu gidermek için görünüyor. – Xaerxess

4

Gerçekten Joda'yı kullanmanız gerekiyor mu? ay adlarını değiştirme standart Java API tarih biçemleyicileri kullanarak oldukça basittir:

SimpleDateFormat sdf = new SimpleDateFormat("'z dnia' dd MMMM yyyy 'r.'"); 

DateFormatSymbols dfs = sdf.getDateFormatSymbols(); 

dfs.setMonths(
    new String[] { 
     "stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", 
     "lipca", "sierpnia", "września", "października", "listopada", 
     "grudnia" 
    }); 

sdf.setDateFormatSymbols(dfs); 

System.out.println(
    sdf.format(new GregorianCalendar(2012, Calendar.DECEMBER, 28).getTime())); 
+1

Joda'yı (şirket önerileri) kullanmayı tercih ediyorum, ayrıca 'SimpleDateFormat' iş parçacığı güvenli değil. Standart JDK Tarih API'sinde ay adlarını değiştirmenin kolay bir yolu olduğu için, Joda ... – Xaerxess