Java dizesinden tarihe dönüştürme

Java'da 'January 2, 2010' biçimindeki bir Stringi bir Datee dönüştürmenin en iyi yolu nedir?

Nihayetinde, ay, gün ve yılı tamsayı olarak ayırmak istiyorum, böylece

Date date = new Date();
date.setMonth()..
date.setYear()..
date.setDay()..
date.setlong currentTime = date.getTime();

tarihi saate dönüştürmek için.

Çözüm

Bu zor bir yoldur ve bu java.util.Date ayarlayıcı yöntemleri Java 1.1'den (1997) beri kullanımdan kaldırılmıştır. Basitçe, giriş dizesiyle eşleşen bir biçim deseni kullanarak SimpleDateFormat kullanarak tarihi biçimlendirin.

Giriş dizesi olarak "January 2, 2010" özel durumunuzda:

  1. "January" tam metin ayıdır, bu nedenle bunun için MMMM kalıbını kullanın
  2. "2" ayın kısa günüdür, bu nedenle bunun için d kalıbını kullanın.
  3. "2010" 4 basamaklı yıldır, bu nedenle bunun için yyyy kalıbını kullanın.
String string = "January 2, 2010";
DateFormat format = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH);
Date date = format.parse(string);
System.out.println(date); // Sat Jan 02 00:00:00 GMT 2010

Açık Locale argümanının önemine dikkat edin. Bunu atlarsanız, girdi dizesinin ay adında kullanıldığı gibi İngilizce olması gerekmeyen varsayılan yerel ayarı kullanacaktır. Yerel ayar giriş dizesiyle eşleşmezse, biçim deseni geçerli görünse bile kafa karıştırıcı bir şekilde bir java.text.ParseException alırsınız.

Burada'javadoc]1'dan ilgili bir alıntı, mevcut tüm biçim kalıplarını listeliyor:

Letter  Date or Time Component  Presentation        Examples
------  ----------------------  ------------------  -------------------------------------
G       Era designator          Text                AD
y       Year                    Year                1996; 96
Y       Week year               Year                2009; 09
M/L     Month in year           Month               July; Jul; 07
w       Week in year            Number              27
W       Week in month           Number              2
D       Day in year             Number              189
d       Day in month            Number              10
F       Day of week in month    Number              2
E       Day in week             Text                Tuesday; Tue
u       Day number of week      Number              1
a       Am/pm marker            Text                PM
H       Hour in day (0-23)      Number              0
k       Hour in day (1-24)      Number              24
K       Hour in am/pm (0-11)    Number              0
h       Hour in am/pm (1-12)    Number              12
m       Minute in hour          Number              30
s       Second in minute        Number              55
S       Millisecond             Number              978
z       Time zone               General time zone   Pacific Standard Time; PST; GMT-08:00
Z       Time zone               RFC 822 time zone   -0800
X       Time zone               ISO 8601 time zone  -08; -0800; -08:00

Kalıpların büyük/küçük harfe duyarlı olduğunu ve dört veya daha fazla karakterden oluşan metin tabanlı kalıpların tam formu temsil ettiğini unutmayın; aksi takdirde, varsa kısa veya kısaltılmış bir form kullanılır. Yani örneğin MMMMM veya daha fazlası gereksizdir.

Burada, verilen bir dizeyi tarihe ayrıştırmak için geçerli SimpleDateFormat kalıplarının bazı örnekleri verilmiştir:

Input string                            Pattern
------------------------------------    ----------------------------
2001.07.04 AD at 12:08:56 PDT           yyyy.MM.dd G 'at' HH:mm:ss z
Wed, Jul 4, '01                         EEE, MMM d, ''yy
12:08 PM                                h:mm a
12 o'clock PM, Pacific Daylight Time    hh 'o''clock' a, zzzz
0:08 PM, PDT                            K:mm a, z
02001.July.04 AD 12:08 PM               yyyyy.MMMM.dd GGG hh:mm aaa
Wed, 4 Jul 2001 12:08:56 -0700          EEE, d MMM yyyy HH:mm:ss Z
010704120856-0700                       yyMMddHHmmssZ
2001-07-04T12:08:56.235-0700            yyyy-MM-dd'T'HH:mm:ss.SSSZ
2001-07-04T12:08:56.235-07:00           yyyy-MM-dd'T'HH:mm:ss.SSSXXX
2001-W27-3                              YYYY-'W'ww-u

Önemli bir not, SimpleDateFormatın **iş parçacığı güvenli olmadığıdır. Başka bir deyişle, onu asla statik veya örnek değişken olarak bildirmemeli ve atamamalı ve daha sonra farklı yöntemlerden / iş parçacıklarından yeniden kullanmamalısınız. Her zaman yöntemin yerel kapsamında yepyeni oluşturmalısınız.


Java 8 güncellemesi

Java 8 veya daha yeni bir sürüm kullanıyorsanız, DateTimeFormatter kullanın (ayrıca burada, önceden tanımlanmış tüm biçimlendiricileri ve mevcut biçim kalıplarını görmek için bağlantıya tıklayın; öğretici burada mevcuttur). Bu yeni API JodaTime'den esinlenmiştir.

String string = "January 2, 2010";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);
LocalDate date = LocalDate.parse(string, formatter);
System.out.println(date); // 2010-01-02

Not: Biçim deseniniz saat kısmını da içeriyorsa LocalDateTime#parse(text, formatter) yerine LocalDate#parse(text, formatter) kullanın. Ve biçim deseniniz saat dilimini de içeriyorsa, bunun yerine ZonedDateTime#parse(text, formatter) kullanın.

Burada'javadoc]3'tan ilgili bir alıntı, mevcut tüm biçim kalıplarını listeliyor:

Symbol  Meaning                     Presentation  Examples
------  --------------------------  ------------  ----------------------------------------------
G       era                         text          AD; Anno Domini; A
u       year                        year          2004; 04
y       year-of-era                 year          2004; 04
D       day-of-year                 number        189
M/L     month-of-year               number/text   7; 07; Jul; July; J
d       day-of-month                number        10

Q/q     quarter-of-year             number/text   3; 03; Q3; 3rd quarter
Y       week-based-year             year          1996; 96
w       week-of-week-based-year     number        27
W       week-of-month               number        4
E       day-of-week                 text          Tue; Tuesday; T
e/c     localized day-of-week       number/text   2; 02; Tue; Tuesday; T
F       week-of-month               number        3

a       am-pm-of-day                text          PM
h       clock-hour-of-am-pm (1-12)  number        12
K       hour-of-am-pm (0-11)        number        0
k       clock-hour-of-am-pm (1-24)  number        0

H       hour-of-day (0-23)          number        0
m       minute-of-hour              number        30
s       second-of-minute            number        55
S       fraction-of-second          fraction      978
A       milli-of-day                number        1234
n       nano-of-second              number        987654321
N       nano-of-day                 number        1234000000

V       time-zone ID                zone-id       America/Los_Angeles; Z; -08:30
z       time-zone name              zone-name     Pacific Standard Time; PST
O       localized zone-offset       offset-O      GMT+8; GMT+08:00; UTC-08:00;
X       zone-offset 'Z' for zero    offset-X      Z; -08; -0830; -08:30; -083015; -08:30:15;
x       zone-offset                 offset-x      +0000; -08; -0830; -08:30; -083015; -08:30:15;
Z       zone-offset                 offset-Z      +0000; -0800; -08:00;

Daha popüler kalıplar için birkaç önceden tanımlanmış biçimlendiriciye sahip olduğunu unutmayın. Örneğin DateTimeFormatter.ofPattern("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH); yerine DateTimeFormatter.RFC_1123_DATE_TIME kullanabilirsiniz. Bu mümkündür, çünkü SimpleDateFormatın aksine, iş parçacığı güvenlidirler. Bu nedenle, gerekirse kendiniz de tanımlayabilirsiniz.

Belirli bir girdi dizesi biçimi için, açık bir DateTimeFormatter kullanmanıza gerek yoktur: 2016-09-26T17:44:57Z gibi standart bir ISO 8601 tarihi, zaten ISO_LOCAL_DATE_TIME biçimlendiricisini kullandığından, doğrudan LocalDateTime#parse(text) ile ayrıştırılabilir. Benzer şekilde, LocalDate#parse(text) bir ISO tarihini zaman bileşeni olmadan ayrıştırır (bkz. ISO_LOCAL_DATE) ve ZonedDateTime#parse(text) bir ISO tarihini bir ofset ve saat dilimi ekleyerek ayrıştırır (bkz. ISO_ZONED_DATE_TIME).

Yorumlar (4)

Ah evet, yine Java Tarihi tartışması. Tarih manipülasyonu ile başa çıkmak için Date, Calendar, GregorianCalendar ve SimpleDateFormat kullanırız. Örneğin Ocak tarihinizi girdi olarak kullanmak gibi:

Calendar mydate = new GregorianCalendar();
String mystring = "January 2, 2010";
Date thedate = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH).parse(mystring);
mydate.setTime(thedate);
//breakdown
System.out.println("mydate -> "+mydate);
System.out.println("year   -> "+mydate.get(Calendar.YEAR));
System.out.println("month  -> "+mydate.get(Calendar.MONTH));
System.out.println("dom    -> "+mydate.get(Calendar.DAY_OF_MONTH));
System.out.println("dow    -> "+mydate.get(Calendar.DAY_OF_WEEK));
System.out.println("hour   -> "+mydate.get(Calendar.HOUR));
System.out.println("minute -> "+mydate.get(Calendar.MINUTE));
System.out.println("second -> "+mydate.get(Calendar.SECOND));
System.out.println("milli  -> "+mydate.get(Calendar.MILLISECOND));
System.out.println("ampm   -> "+mydate.get(Calendar.AM_PM));
System.out.println("hod    -> "+mydate.get(Calendar.HOUR_OF_DAY));

Sonra bunu aşağıdaki gibi bir şeyle manipüle edebilirsiniz:

Calendar now = Calendar.getInstance();
mydate.set(Calendar.YEAR,2009);
mydate.set(Calendar.MONTH,Calendar.FEBRUARY);
mydate.set(Calendar.DAY_OF_MONTH,25);
mydate.set(Calendar.HOUR_OF_DAY,now.get(Calendar.HOUR_OF_DAY));
mydate.set(Calendar.MINUTE,now.get(Calendar.MINUTE));
mydate.set(Calendar.SECOND,now.get(Calendar.SECOND));
// or with one statement
//mydate.set(2009, Calendar.FEBRUARY, 25, now.get(Calendar.HOUR_OF_DAY), now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
System.out.println("mydate -> "+mydate);
System.out.println("year   -> "+mydate.get(Calendar.YEAR));
System.out.println("month  -> "+mydate.get(Calendar.MONTH));
System.out.println("dom    -> "+mydate.get(Calendar.DAY_OF_MONTH));
System.out.println("dow    -> "+mydate.get(Calendar.DAY_OF_WEEK));
System.out.println("hour   -> "+mydate.get(Calendar.HOUR));
System.out.println("minute -> "+mydate.get(Calendar.MINUTE));
System.out.println("second -> "+mydate.get(Calendar.SECOND));
System.out.println("milli  -> "+mydate.get(Calendar.MILLISECOND));
System.out.println("ampm   -> "+mydate.get(Calendar.AM_PM));
System.out.println("hod    -> "+mydate.get(Calendar.HOUR_OF_DAY));
Yorumlar (1)

SimpleDateFormat sınıfı ile uğraşırken, Date'in iş parçacığı güvenli olmadığını ve tek bir Date nesnesini birden fazla iş parçacığı ile paylaşamayacağınızı hatırlamak önemlidir.

Ayrıca "m" ile "M" arasında büyük fark vardır; burada dakikalar için küçük harf, aylar için büyük harf kullanılır. Aynı şey "d" ve "D" için de geçerlidir. Bu, genellikle gözden kaçan ince hatalara neden olabilir. Daha fazla ayrıntı için Javadoc veya Java'da Dizeyi Tarihe Dönüştürme Kılavuzu bölümlerine bakın.

Yorumlar (2)