2017-09-21 17 views
10

tarafından varlığını sürdürüyor Joda-Time'dan Java 8 java.time'a varolan bir uygulamayı yüklüyorum.DateTimeFormatter weekday, bir

Bir 'hafta günü' değeri içeren bir tarih/saat dizesini ayrıştırmanın birim testlerimde bir istisna tetiklediği bir sorunla karşılaştım.

ayrıştırma zaman:

2016-12-21 20:50:25 Çarşamba Aralık +0000 3

biçimini kullanarak:

yyyy'-'MM'-'dd' 'HH':'mm':'ss' 'EEEE' 'MMMM' 'ZZ' 'e 

alıyorum:

java.time.format.DateTimeParseException: 
Text '2016-12-21 20:50:25 Wednesday December +0000 3' 
could not be parsed: Conflict found: 
Field DayOfWeek 3 differs from DayOfWeek 2 derived from 2016-12-21 

Ne zaman ing DateTimeFormatter o beklediği gösterir:

String logline  = "2016-12-21 20:50:25 Wednesday December +0000"; 
String format  = "yyyy'-'MM'-'dd' 'HH':'mm':'ss' 'EEEE' 'MMMM' 'ZZ"; 
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format).withLocale(Locale.ENGLISH);; 
ZonedDateTime dateTime = formatter.parse(logline, ZonedDateTime::from); 

format  = "yyyy'-'MM'-'dd' 'HH':'mm':'ss' 'EEEE' 'MMMM' 'ZZ' 'e"; 
formatter = DateTimeFormatter.ofPattern(format).withLocale(Locale.ENGLISH); 
System.out.println(formatter.format(dateTime)); 

Şimdi bu çıktıyı almak:

2016-12-21 20:50:25 Wednesday December +0000 4 

Yani etkili bir sorunun asıl nedeni Joda-Time e bayrak 1 olmak üzere Pazartesi günü olarak kabul edildiğidir yine de Java 8 java.time, Pazartesi gününü 0 olarak kabul eder. java.time.DateTimeFormatter ben hem the Oracle documentation ve JSR-310 bu bulmak destekleyen modelleri için Şimdi

:

e/c  localized day-of-week  number/text  2; 02; Tue; Tuesday; T 

Bu açık 2 örneği ve 'Salı' beni inandıramaz Çarşamba günü gerektiğini de java. zaman 4 yerine 3 olmalıdır.

Burada sorun nedir? Yanlış anlıyor muyum? Bu, Java 8'deki bir hata mı?

+7

Ne zaman dilimi/locale kullanıyorsunuz, dokümanın haftanın yerelleştirilmiş günü olduğunu belirttiği gibi, bazı yereller pazartesi günü pazartesiye başlıyor – hardillb

+0

pazartesi gününün aksine .wifyLocale (Locale.ENGLISH) ekledim; kodda. –

cevap

6

Joda-Zaman ve java.time desen e yorumladığı nasıl bir fark var olan haftanın ilk gününü kontrol edebilirsiniz.

Joda-Zamanda

, e desen designates the numeric value of day-of-week: Yani

Symbol Meaning  Presentation Examples 
------ ----------- ------------ ------- 
e  day of week number  2 

, e Bir tarih nesneden haftanın gününü elde eşdeğerdir kullanarak:

// using org.joda.time.DateTime and org.joda.time.format.DateTimeFormat 
DateTime d = new DateTime(2016, 12, 21, 20, 50, 25, 0, DateTimeZone.UTC); 
DateTimeFormatter fmt = DateTimeFormat.forPattern("e").withLocale(Locale.ENGLISH); 
System.out.println(d.toString(fmt)); // 3 
System.out.println(d.getDayOfWeek()); // 3 
System.out.println(d.dayOfWeek().getAsText(Locale.ENGLISH)); // Wednesday 

Not Hem biçimlendirici hem de getDayOfWeek(), 3'u döndürür. getDayOfWeek() method, DateTimeConstants class ve Wednesday's value is 3 (numaralı telefonlara göre numaralı belgede) tanımlanan bir değer döndürür.java.time API olarak


, desen ehas a different meaning:

Pattern Count Equivalent builder methods 
------- ----- -------------------------- 
e  1  append special localized WeekFields element for numeric day-of-week 

Lokalize WeekFields elemanı kullanır ve bu yerel olarak değişebilir. biçimlendirici İngiliz yerel ayar için haftanın yerelleştirilmiş gün kullanılıyor

ZonedDateTime z = ZonedDateTime.of(2016, 12, 21, 20, 50, 25, 0, ZoneOffset.UTC); 
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("e", Locale.ENGLISH); 
System.out.println(z.format(fmt)); // 4 
System.out.println(z.getDayOfWeek()); // WEDNESDAY 
System.out.println(z.getDayOfWeek().getValue()); // 3 

Not olduğunu ve getDayOfWeek().getValue() döner 3 çağrısında değeri 4 geçerli: getDayOfWeek() yöntemine göre davranış farklı olabilir. İngilizce yerel ile e kullanmaya eş değerdir çünkü var

bir java.time.temporal.WeekFields: ISO'nun tanımı ilk günü olarak Pazartesi kullanması nedeniyle var

// same as getDayOfWeek() 
System.out.println(z.get(WeekFields.ISO.dayOfWeek())); // 3 

: ISO'nun tanımı kullanarak eşdeğerdir

// using localized fields 
WeekFields wf = WeekFields.of(Locale.ENGLISH); 
System.out.println(z.get(wf.dayOfWeek())); // 4 

getDayOfWeek() iken haftası, WeekFields, ingilizce yerel saati ile kullanılır. Pazar:

// comparing the first day of week 
System.out.println(WeekFields.ISO.getFirstDayOfWeek()); // MONDAY 
System.out.println(wf.getFirstDayOfWeek()); // SUNDAY 

e desen, biçimlendiricideki (veya hiçbiri ayarlanmamışsa, JVM varsayılan yerel ayarı) ayarlanan yerel ayarlara göre farklı şekilde davranabilir veya getDayOfWeek() yapamaz.

WeekFields.of(Locale.FRENCH).getFirstDayOfWeek(); // MONDAY 
WeekFields.of(new Locale("ar", "AE")).getFirstDayOfWeek(); // SATURDAY 

göre javadoc için, sayısal bir değer döndürür sadece desenler bazı arap yerellerde, haftanın ilk günü Cumartesi iken Fransız yerelinde, örneğin, sadece ISO gibi davranır Haftanın günü için yerelleştirilmiş olanlar gibi görünüyor.

String input = "2016-12-21 20:50:25 Wednesday December +0000 3"; 
DateTimeFormatter parser = new DateTimeFormatterBuilder() 
    // date/time pattern 
    .appendPattern("yyyy-MM-dd HH:mm:ss EEEE MMMM ZZ ") 
    // numeric day of week 
    .appendValue(ChronoField.DAY_OF_WEEK) 
    // create formatter with English locale 
    .toFormatter(Locale.ENGLISH); 

ZonedDateTime date = ZonedDateTime.parse(input, parser); 

: Yani giriş 2016-12-21 20:50:25 Wednesday December +0000 3 ayrıştırmak için, haftanın gününe (ISO olmayan yerel duyarlı alanı) sayısal değerini belirtmek için bir java.time.format.DateTimeFormatterBuilder kullanabilir ve java.time.temporal.ChronoField ile tarih/saat desen katılabilir Ayrıca, -, : ve boşluk karakterlerini belirtmeniz gerekmediğinden, desen daha net ve okunabilir hale gelir (IMO).

Ayrıca, ingilizce yerel ayarını da yapıyorum, çünkü ayarlamazsanız, JVM varsayılan yerel ayarını kullanır ve her zaman İngilizce olması garanti edilmez. Ayrıca, çalışma zamanında bile haber verilmeksizin değiştirilebilir, bu nedenle, girişin hangi dilde olduğunu biliyorsanız, özellikle belirtmek daha iyidir.


Güncelleme: o (JDK 1.8.0_144) appendText(ChronoField.DAY_OF_WEEK, TextStyle.NARROW_STANDALONE) ve benim testlerde eşdeğer muhtemelen ccccc desen döndürür (ve ayrıca ayrıştırır), çalışması gerekir 3:

DateTimeFormatter parser = DateTimeFormatter 
    .ofPattern("yyyy-MM-dd HH:mm:ss EEEE MMMM ZZ ccccc", Locale.ENGLISH); 
ZonedDateTime date = ZonedDateTime.parse(input, parser); 
+1

Teşekkürler. Bu açıklama gerçekten yardımcı oluyor. Bunun gibi tüm bu alanlardan alıntı yapıyorum, çünkü bu ifade strftime formatlı bir giriş dizesinden üretiliyor. Her şeyin doğru çalışması için bu değerleri eklemenin bir yolunu bulmalıyım. Bkz. Https://github.com/nielsbasjes/logparser/blob/master/httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/StrfTimeStampDissector.java#L200 –

+2

@NielsBasjes Hoşgeldiniz, yardım etmekten memnunum! Bazı testler yaptım ve belki de "ccccc" kelimesi ihtiyacın olan şey olmalı. Cevabı güncelledim. –

1

Locale.ENGLISH'da Çarşamba, haftanın 4. günüdür ve hafta Pazar günü başlar. Sen

WeekFields.of(Locale.ENGLISH).getFirstDayOfWeek(); //it's SUNDAY 
İlgili konular