ฉันจะรับวันที่และเวลาปัจจุบันเป็น UTC หรือ GMT ใน Java ได้อย่างไร


479

เมื่อฉันสร้างDateวัตถุใหม่มันจะเริ่มต้นเวลาปัจจุบัน แต่ในเขตเวลาท้องถิ่น ฉันจะรับวันที่และเวลาปัจจุบันเป็น GMT ได้อย่างไร


ฉันรู้ว่าประเภทของหัวข้อเหล่านี้ถูกกล่าวถึงอย่างสมบูรณ์ แต่ฉันพบว่าแพคเกจ Commons-lang จัดการกับปัญหา Java ทั่วไปเหล่านี้ได้ดี commons.apache.org/lang/api-2.5/org/apache/commons/lang/timeลองดูแพ็คเกจที่พวกเขามี

คุณต้องการเวลาท้องถิ่นใดและความแม่นยำเท่าใด เขตเวลาส่วนใหญ่จะถูกกำหนดให้สัมพันธ์กับ UTC ด้วยค่าออฟเซ็ตคงที่วัดในSIวินาที แต่ความสัมพันธ์ของ GMT ซึ่งขึ้นอยู่กับการสังเกตแสงอาทิตย์และ a (เล็กน้อย) ความยาวของตัวแปรที่สองมีความซับซ้อนมากขึ้น ทั้งสองต่างกันมากถึง 0.9 วินาที
mc0e

1
Dateไม่ถือโซนเวลาดังนั้น "แต่ในเขตเวลาท้องถิ่น” ไม่ถูกต้อง (หรือไม่ถูกต้องที่ดีที่สุด) ดู. ทุกอย่างเกี่ยวกับ java.util.Date .
Ole VV

คำตอบ:


409

java.util.Dateไม่มีเขตเวลาที่เฉพาะเจาะจงแม้ว่าค่าของมันมักจะคิดว่าเกี่ยวข้องกับ UTC อะไรทำให้คุณคิดว่าเป็นเวลาท้องถิ่น

เพื่อความแม่นยำ: ค่าภายในjava.util.Dateคือจำนวนมิลลิวินาทีนับตั้งแต่ยุค Unix ซึ่งเกิดขึ้นในเวลาเที่ยงคืนของวันที่ 1 มกราคม 1970 UTC สามารถอธิบายยุคสมัยเดียวกันได้ในเขตเวลาอื่น แต่คำอธิบายดั้งเดิมอยู่ในรูปของ UTC เนื่องจากเป็นจำนวนมิลลิวินาทีนับตั้งแต่เวลาตายตัวค่าภายในjava.util.Dateจึงเหมือนกันทั่วโลกในทุกช่วงเวลาโดยไม่คำนึงถึงเขตเวลาท้องถิ่น

ฉันสงสัยว่าปัญหาคือคุณกำลังแสดงผ่านอินสแตนซ์ของปฏิทินที่ใช้เขตเวลาท้องถิ่นหรืออาจใช้Date.toString()ซึ่งใช้เขตเวลาท้องถิ่นหรือตามSimpleDateFormatตัวอย่างซึ่งตามค่าเริ่มต้นแล้วก็ใช้เขตเวลาท้องถิ่นด้วย

หากนี่ไม่ใช่ปัญหาโปรดโพสต์โค้ดตัวอย่างบางส่วน

อย่างไรก็ตามฉันขอแนะนำให้คุณใช้Joda-Timeต่อไปซึ่งมี API ที่ชัดเจนกว่ามาก


5
นั่นอาจเป็นปัญหาไดรเวอร์ คุณอาจต้องตั้งค่าการเชื่อมต่อเป็น UTC หรืออะไรทำนองนั้น ฉันเคยเห็นปัญหาเช่นนี้มาก่อน แต่ปัญหาไม่ได้อยู่ใน java.util.Date
Jon Skeet

13
ก่อนหน้านี้ตามstackoverflow.com/questions/4123534/…ไดรเวอร์ MySQL JDBC จะแปลงค่าที่ระบุjava.util.Timestamp(หรือjava.util.Date) เป็นเขตเวลาของเซิร์ฟเวอร์
Derek Mahar

5
@นาย. Cat: คุณเป็นคนตัดสินอย่างไร มันคือการเขียนSystem.out.println(new Date())? หากเป็นเช่นนั้นคุณควรทราบว่าเป็นtoString()วิธีการที่ใช้เขตเวลาที่นั่น ... หากไม่ใช่โปรดระบุรายละเอียดเพิ่มเติม
Jon Skeet

8
@KanagaveluSugumar: toString()ใช้เขตเวลาเริ่มต้นเสมอ date.getTime()ส่งคืนมิลลิวินาทีนับตั้งแต่ยุค Unix ใน UTC อย่างแน่นอน มันถูกต้องที่สุดที่จะบอกว่าDateตัวเองไม่มีเขตเวลาเลย - เป็นเพียงทันเวลาทันเวลาซึ่งอาจถูกพิจารณาในหลายเขตเวลา แต่เมื่อคุณสร้างอินสแตนซ์มันไม่ได้ขึ้นอยู่กับเขตเวลาของคุณ
Jon Skeet

6
@Jemenake: จริง ๆ แล้วมันไม่ได้เกิดขึ้นเมื่อตอนเที่ยงคืนของกรีนนิชเพราะสหราชอาณาจักรอยู่ในเวลา UTC + 1 เพียงหนึ่งในบิตแปลก ๆ ของประวัติศาสตร์ แต่ฉันเอาประเด็นของคุณ - ดีกว่าที่จะพูดว่า "new Date (). getTime () ส่งคืนมิลลิวินาทีนับตั้งแต่ยุค Unix ซึ่งเป็นเวลาเที่ยงคืนเมื่อวันที่ 1 มกราคม 1970 UTC" ดังนั้น UTC จึงเป็นส่วนหนึ่งของการตรึงยุคเพื่อให้ทันเวลาโดยเฉพาะไม่ใช่ส่วนหนึ่งของผลลัพธ์
Jon Skeet

324

TL; DR

Instant.now()   // Capture the current moment in UTC. 

สร้าง String เพื่อแทนค่านั้น:

Instant.now().toString()  

2016-09-13T23: 30: 52.123Z

รายละเอียด

ในฐานะที่เป็นคำตอบที่ถูกต้องโดยจอนสกีตกล่าวว่าวัตถุ java.util.Date มีโซนเวลา แต่toStringการนำไปใช้นั้นจะใช้เขตเวลาเริ่มต้นของ JVM เมื่อสร้างการแทนค่าสตริงของค่าวันที่และเวลา วันที่สับสนกับโปรแกรมเมอร์ไร้เดียงสา Date ดูเหมือนจะมีเขตเวลา แต่ไม่มี

The java.util.Date, j.u.Calendarและjava.text.SimpleDateFormatคลาสที่รวมกับ Java นั้นมีปัญหาอย่างมาก หลีกเลี่ยงพวกเขา ใช้ไลบรารีวันที่และเวลาที่มีความสามารถเหล่านี้แทน

java.time (Java 8)

Java 8นำเสนอแพ็คเกจ java.time. *ใหม่ที่ยอดเยี่ยมเพื่อแทนที่คลาส java.util.Date/Calendar เก่า

รับเวลาปัจจุบันใน UTC / GMT เป็นหนึ่งซับ ...

Instant instant = Instant.now();

ว่าInstantชั้นเป็นอาคารบล็อกพื้นฐานใน java.time คิดเป็นช่วงเวลาบนไทม์ไลน์ในส่วนUTCมีความละเอียดของนาโนวินาที

ใน Java 8 เวลาปัจจุบันจะถูกจับด้วยความละเอียดสูงสุดมิลลิวินาทีเท่านั้น Java 9 นำการใช้งานใหม่ของการClockจับภาพช่วงเวลาปัจจุบันไปจนถึงความสามารถระดับนาโนวินาทีแบบเต็มของคลาสนี้ขึ้นอยู่กับความสามารถของฮาร์ดแวร์นาฬิกาในคอมพิวเตอร์โฮสต์ของคุณ

toStringเมธอดIt's สร้างการแทนค่าสตริงโดยใช้รูปแบบ ISO 8601 เฉพาะรูปแบบเดียว รูปแบบนั้นจะแสดงผลลัพธ์เป็นศูนย์, สาม, หกหรือเก้าหลัก ( มิลลิวินาที , ไมโครวินาทีหรือนาโนวินาที ) ตามความจำเป็นเพื่อแสดงเศษส่วนของวินาที

หากคุณต้องการการจัดรูปแบบที่มีความยืดหยุ่นมากขึ้นหรือคุณสมบัติเพิ่มเติมอื่น ๆ แล้วใช้การ UTC ชดเชยจากศูนย์สำหรับ UTC ตัวเอง ( ZoneOffset.UTCคงที่ ) OffsetDateTimeเพื่อให้ได้

OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );

ถ่ายโอนข้อมูลไปยังคอนโซล ...

System.out.println( "now.toString(): " + now );

เมื่อวิ่ง ...

now.toString(): 2014-01-21T23:42:03.522Z

ตารางประเภทวันที่ - เวลาใน Java ทั้งทันสมัยและดั้งเดิม


เกี่ยวกับjava.time

java.timeกรอบถูกสร้างขึ้นใน Java 8 และต่อมา ชั้นเรียนเหล่านี้แย่งลำบากเก่ามรดกเรียนวันที่เวลาเช่นjava.util.Date, และCalendarSimpleDateFormat

ต้องการเรียนรู้เพิ่มเติมโปรดดูที่ออราเคิลกวดวิชา และค้นหา Stack Overflow สำหรับตัวอย่างและคำอธิบายมากมาย สเปกJSR 310

Joda เวลาโครงการขณะนี้อยู่ในโหมดการบำรุงรักษาให้คำแนะนำแก่การโยกย้ายไปยังjava.timeชั้นเรียน

คุณสามารถแลกเปลี่ยนวัตถุjava.timeโดยตรงกับฐานข้อมูลของคุณ ใช้ไดรเวอร์ JDBC ที่สอดคล้องกับJDBC 4.2หรือใหม่กว่า ไม่จำเป็นต้องใช้สตริงไม่จำเป็นต้องมีjava.sql.*คลาส

จะรับคลาส java.time ได้ที่ไหน?

  • Java SE 8 , Java SE 9 , Java SE 10 , Java SE 11และใหม่กว่า - ส่วนหนึ่งของ Java API มาตรฐานที่มีการใช้งานแบบรวม
    • Java 9 เพิ่มคุณสมบัติและการแก้ไขเล็กน้อย
  • Java SE 6และ Java SE 7
    • ส่วนใหญ่ของjava.timeการทำงานจะกลับรังเพลิง Java 6 และ 7 ในThreeTen-ย้ายกลับ
  • Android

ตารางที่ไลบรารี java.time ใดที่จะใช้กับเวอร์ชันของ Java หรือ Android

โครงการThreeTen-Extraขยาย java.time ด้วยคลาสเพิ่มเติม โครงการนี้เป็นพื้นฐานที่พิสูจน์ได้สำหรับการเพิ่มเติมในอนาคตไปยัง java.time คุณอาจพบว่าการเรียนที่มีประโยชน์บางอย่างที่นี่เช่นInterval, YearWeek, YearQuarterและอื่น ๆ อีกมากมาย


Joda เวลา

UPDATE: โครงการJoda-Timeในขณะนี้อยู่ในโหมดบำรุงรักษาแนะนำการโยกย้ายไปยังคลาสjava.time

การใช้ไลบรารีโอเพนซอร์สฟรีของต้นทุนJoda-Timeของบุคคลที่สามคุณสามารถรับวันที่ปัจจุบันได้ด้วยรหัสเพียงบรรทัดเดียว

Joda-Time สร้างคลาส java.time. * ใหม่ใน Java 8 แต่มีสถาปัตยกรรมที่แตกต่างกัน คุณสามารถใช้ Joda-Time กับ Java เวอร์ชันเก่าได้ Joda-Time ยังคงทำงานใน Java 8 และยังคงได้รับการบำรุงรักษาอย่างต่อเนื่อง (จนถึงปี 2014) อย่างไรก็ตามทีม Joda-Time ไม่แนะนำให้โยกย้ายไปยัง java.time

System.out.println( "UTC/GMT date-time in ISO 8601 format: " + new org.joda.time.DateTime( org.joda.time.DateTimeZone.UTC ) );

โค้ดตัวอย่างที่มีรายละเอียดเพิ่มเติม (Joda-Time 2.3) ...

org.joda.time.DateTime now = new org.joda.time.DateTime(); // Default time zone.
org.joda.time.DateTime zulu = now.toDateTime( org.joda.time.DateTimeZone.UTC );

ถ่ายโอนข้อมูลไปยังคอนโซล ...

System.out.println( "Local time in ISO 8601 format: " + now );
System.out.println( "Same moment in UTC (Zulu): " + zulu );

เมื่อวิ่ง ...

Local time in ISO 8601 format: 2014-01-21T15:34:29.933-08:00
Same moment in UTC (Zulu): 2014-01-21T23:34:29.933Z

สำหรับรหัสตัวอย่างเพิ่มเติมที่ใช้ในเขตเวลาทำงานให้ดูคำตอบของคำถามที่คล้ายกัน

เขตเวลา

ฉันขอแนะนำให้คุณระบุเขตเวลาเสมอแทนที่จะพึ่งพาปริยายในเขตเวลาเริ่มต้นปัจจุบันของ JVM (ซึ่งสามารถเปลี่ยนแปลงได้ตลอดเวลา!) การพึ่งพาเช่นนี้ดูเหมือนจะเป็นสาเหตุของความสับสนและข้อบกพร่องในงานวันเวลา

เมื่อโทรnow()ผ่านเขตเวลาที่ต้องการ / ที่คาดไว้ ใช้DateTimeZoneคลาส

DateTimeZone zoneMontréal = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( zoneMontréal );

คลาสนั้นมีค่าคงที่สำหรับเขตเวลาUTC

DateTime now = DateTime.now( DateTimeZone.UTC );

หากคุณต้องการใช้เขตเวลาเริ่มต้นปัจจุบันของ JVM อย่างแท้จริงให้โทรออกอย่างชัดเจนเพื่อให้รหัสของคุณเป็นเอกสารด้วยตนเอง

DateTimeZone zoneDefault = DateTimeZone.getDefault();

ISO 8601

อ่านเกี่ยวกับรูปแบบISO 8601 ทั้ง java.time และ Joda-Time ใช้รูปแบบที่สมเหตุสมผลของมาตรฐานนั้นเป็นค่าเริ่มต้นสำหรับทั้งการแยกวิเคราะห์และการสร้างสตริง


จริง java.util.Date จะมีโซนเวลาที่ฝังอยู่ลึกลงไปใต้ชั้นของรหัสที่มา สำหรับจุดประสงค์เชิงปฏิบัติส่วนใหญ่เขตเวลานั้นจะถูกข้ามไป ดังนั้นตามชวเลขเราบอกว่า java.util.Date ไม่มีเขตเวลา นอกจากนี้เขตเวลาที่ฝังไม่ได้ใช้โดยtoStringวิธีของวันที่ วิธีการนั้นใช้เขตเวลาเริ่มต้นปัจจุบันของ JVM เหตุผลเพิ่มเติมทั้งหมดเพื่อหลีกเลี่ยงคลาสที่สับสนและใช้ Joda-Time และ java.time


2
DateTime.now().toDateTime(DateTimeZone.UTC)เป็นสิ่งที่ฉันกำลังมองหา! ขอบคุณ!
Managarm

1
@Managarm คุณสามารถย่อให้สั้นลงไปที่: DateTime nowUtc = DateTime.now ( DateTimeZone.UTC ) ;
Basil Bourque

วิธีรับสิ่งนี้ด้วย Pure Java 8 2014-01-21T15:34:29.933-08:00ในตัวอย่างที่คุณใช้new org.joda.time.DateTime()
GOXR3PLUS

1
@ GOXR3PLUS ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) ).truncatedTo( ChronoUnit.MILLIS ).toOffsetDateTime().toString() เราได้รับช่วงเวลาปัจจุบันสำหรับเขตเวลาที่ระบุ ถัดไปลพบุรีไมโคร / nanos ใด ๆ จากนั้นเราแปลงเป็นเพียงการชดเชยจาก UTC เพียง (จำนวนชั่วโมง - นาที - วินาที) แทนที่จะเป็นเขตเวลาเต็มเป่า (ประวัติของอดีตปัจจุบันและการเปลี่ยนแปลงในอนาคตในการชดเชยที่ใช้โดยคนของ ภูมิภาคเฉพาะ) สุดท้ายเราสร้างข้อความที่แสดงถึงค่าในOffsetDateTimeรูปแบบ ISO 8601 มาตรฐานที่ใช้โดยค่าเริ่มต้นในtoStringวิธีการของมัน
Basil Bourque

ขอบคุณที่ให้คำอธิบายรายละเอียดนี้และ +1 สำหรับ Android ที่สนับสนุน :) @BasilBourque
mochadwi

271
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));

//Local time zone   
SimpleDateFormat dateFormatLocal = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");

//Time in GMT
return dateFormatLocal.parse( dateFormatGmt.format(new Date()) );

11
ทำไมคุณถึงวิเคราะห์ด้วย dateFormatLocal หลังจากใช้รูปแบบ dateFormatGmt ... ไม่สมเหตุสมผลโดยการอ่าน ฉันแน่ใจว่ามันใช้งานได้ แต่แค่สงสัย?
MindWire

2
setTimeZone ทำ (ฉันเดาว่าคุณสามารถใช้ getTimeZone ("UTC") เหมือนกับ GMT ได้ไหม)
rogerdpack

6
แต่เวลาขึ้นอยู่กับเวลาที่ตั้งไว้ของอุปกรณ์ หากผู้ใช้มีเวลาที่ผิดชุดบนอุปกรณ์ของเขาแล้วคุณจะได้รับ UTC ผิด .correct ฉันฉันผิดถ้า
Basavaraj Hampali

@BasavarajHampali แต่ในโลกปัจจุบันอุปกรณ์ส่วนใหญ่เชื่อมต่อกับอินเทอร์เน็ตซึ่งแก้ไขเวลาไม่ถูกต้อง
Akshat Agarwal

3
ไม่มีความแตกต่างของเวลาระหว่างเวลาสากลเชิงพิกัด (UTC) และเวลามาตรฐานกรีนิช (GMT)
slott

86

ส่งคืนเวลา UTC อย่างแน่นอน: เป็นวัตถุ String และ Date!

static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

public static Date getUTCdatetimeAsDate() {
    // note: doesn't check for null
    return stringDateToDate(getUTCdatetimeAsString());
}

public static String getUTCdatetimeAsString() {
    final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
    final String utcTime = sdf.format(new Date());

    return utcTime;
}

public static Date stringDateToDate(String StrDate) {
    Date dateToReturn = null;
    SimpleDateFormat dateFormat = new SimpleDateFormat(DATEFORMAT);

    try {
        dateToReturn = (Date)dateFormat.parse(StrDate);
    }
    catch (ParseException e) {
        e.printStackTrace();
    }

    return dateToReturn;
}

ในคำตอบของฉันฉันลืมที่จะแสดงวิธีกำหนด DATEFORMAT: static final String DATEFORMAT = "yyyy-MM-dd HH:mm:ss";
บางคนที่ไหนสักแห่ง

21
โปรดหลีกเลี่ยงการเริ่มต้นชื่อเมธอดด้วยตัวพิมพ์ใหญ่ใน Java โปรดดูระเบียบวิธีการโค้ด Javaสำหรับชื่อ
Florian Schrofner

2
เมื่อเปลี่ยนเส้นทางไปยังคำตอบนี้การโทรnew Date()จะไม่ส่งคืนเวลา UTC ที่ถูกต้องหากเวลาอุปกรณ์ผิด
Sanoop

วิธีนี้ทำให้เวลาขึ้นอยู่กับปฏิทินของอุปกรณ์?
อาร์โนลด์บราวน์

สิ่งหนึ่งที่ควรทราบ โซลูชันใด ๆ ที่ต้องการรับ Date หรือ Timestamp ใน UTC ดูเหมือนว่ากุญแจคือการไม่ใช้ SimpleDateFormat อีกครั้ง แต่ควรใช้หนึ่งเพื่อรับ UTC เป็นสตริงจากนั้นสร้าง UTC ใหม่เมื่อแปลงสตริงเป็น Date หรือวัตถุการประทับเวลา ฉันสังเกตเห็นว่าถ้าคุณพยายามที่จะใช้ SimpleDateFormat เดียวกันซ้ำดังนั้นวันที่ / เวลาประทับวัตถุที่เป็นผลลัพธ์จะเปลี่ยนกลับไปเป็นเขตเวลาท้องถิ่นแทน UTC
Brian Begun

65
    Calendar c = Calendar.getInstance();
    System.out.println("current: "+c.getTime());

    TimeZone z = c.getTimeZone();
    int offset = z.getRawOffset();
    if(z.inDaylightTime(new Date())){
        offset = offset + z.getDSTSavings();
    }
    int offsetHrs = offset / 1000 / 60 / 60;
    int offsetMins = offset / 1000 / 60 % 60;

    System.out.println("offset: " + offsetHrs);
    System.out.println("offset: " + offsetMins);

    c.add(Calendar.HOUR_OF_DAY, (-offsetHrs));
    c.add(Calendar.MINUTE, (-offsetMins));

    System.out.println("GMT Time: "+c.getTime());

52

ไม่ใช่เวลาจริง แต่อาจมีการเปลี่ยนแปลงการแสดง

SimpleDateFormat f = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
f.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(f.format(new Date()));

เวลาจะเหมือนกันในทุกจุดของโลก แต่การรับรู้เวลาของเราอาจแตกต่างกันไปขึ้นอยู่กับสถานที่


ใช่วิธีการแก้ปัญหาที่ดีและสะอาด มันเป็นเพียงความกังวลของฉันถ้ามันไม่มีประสิทธิภาพในการสร้างวัตถุวันที่ใหม่แทนที่จะได้รับอินสแตนซ์ปฏิทิน?
Beemo

มันจะได้รับการปรับให้เหมาะสมโดย JVM และ HotSpot จะรันโค้ด x86 ที่มีประสิทธิภาพที่สุดเท่าที่จะเป็นไปได้
Antonio

17

ปฏิทิน aGMTCalendar = Calendar.getInstance (TimeZone.getTimeZone ("GMT")); จากนั้นการดำเนินการทั้งหมดที่ดำเนินการโดยใช้วัตถุ aGMTCalendar จะดำเนินการกับเขตเวลา GMT และจะไม่มีการปรับเวลาตามฤดูกาลหรือการออฟเซ็ตคงที่

ไม่ถูกต้อง!

Calendar aGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
aGMTCalendar.getTime(); //or getTimeInMillis()

และ

Calendar aNotGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT-2"));aNotGMTCalendar.getTime();

จะกลับมาในเวลาเดียวกัน รหัสสำหรับ

new Date(); //it's not GMT.

17

รหัสนี้จะพิมพ์เวลา UTC ปัจจุบัน

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;


public class Test
{
    public static void main(final String[] args) throws ParseException
    {
        final SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
        f.setTimeZone(TimeZone.getTimeZone("UTC"));
        System.out.println(f.format(new Date()));
    }
}

ผลลัพธ์

2013-10-26 14:37:48 UTC

14

ใช้งานได้กับ UTC มิลลิวินาทีใน Android

Calendar c = Calendar.getInstance();
int utcOffset = c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET);  
Long utcMilliseconds = c.getTimeInMillis() + utcOffset;

7
คุณเพียงแค่ต้องลบออฟเซ็ต?
tevch

c.add(Calendar.MILLISECOND, (-utcOffset))การรับปฏิทินด้วยเขตเวลา
utc

10

นี่คือสิ่งที่ดูเหมือนจะไม่ถูกต้องในคำตอบของจอนสกีต เขาพูดว่า:

java.util.Dateอยู่เสมอใน UTC อะไรทำให้คุณคิดว่าเป็นเวลาท้องถิ่น ฉันสงสัยว่าปัญหาคือคุณกำลังแสดงผ่านอินสแตนซ์ของปฏิทินที่ใช้เขตเวลาท้องถิ่นหรืออาจใช้ Date.toString()ซึ่งใช้เขตเวลาท้องถิ่นด้วย

อย่างไรก็ตามรหัส:

System.out.println(new java.util.Date().getHours() + " hours");

ให้เวลาท้องถิ่นไม่ใช่ GMT (เวลา UTC) โดยใช้ no Calendarและ no SimpleDateFormatเลย

นั่นคือเหตุผลที่ดูเหมือนว่าบางสิ่งไม่ถูกต้อง

รวบรวมคำตอบไว้ด้วยกันรหัส:

System.out.println(Calendar.getInstance(TimeZone.getTimeZone("GMT"))
                           .get(Calendar.HOUR_OF_DAY) + " Hours");

แสดงเวลา GMT แทนที่จะเป็นชั่วโมงท้องถิ่น - โปรดทราบว่าgetTime.getHours()จะหายไปเพราะจะสร้างDate()วัตถุซึ่งตามหลักวิชาจะเก็บวันที่ใน GMT แต่ให้เวลาในโซนเวลาท้องถิ่นกลับมา


6
ฉันไม่เคยเห็นคำตอบนี้มาก่อน แต่ถ้าคุณอ่านเอกสารสำหรับDate.getHours()วิธีการที่เลิกใช้แล้วจะทำให้ชัดเจนมาก: "ค่าที่ส่งคืนคือตัวเลข (0 ถึง 23) แทนชั่วโมงภายในวันที่มีหรือเริ่มต้นด้วย แสดงเวลาทันทีโดยวัตถุ Date นี้ดังที่ตีความในเขตเวลาท้องถิ่น " (เน้นของฉัน) มันเป็นgetHours()วิธีที่ตีความค่าภายในเขตเวลาท้องถิ่น - มันไม่ได้เป็นส่วนหนึ่งของสถานะของDateวัตถุเอง
Jon Skeet

2
ในฐานะที่เป็นจอนสกีตที่ระบุไว้อย่างถูกต้องวัตถุ java.util.Date มีโซนเวลาไม่นาน แต่วิธีการที่สับสนtoStringและgetHoursใช้เขตเวลาเริ่มต้นกับผลลัพธ์ของพวกเขา ดังนั้นโปรแกรมเมอร์ของnaïveจึงถูกหลอกได้ง่ายเหมือนว่า Date มีเขตเวลา แต่จริงๆแล้วไม่มี
Basil Bourque

7

หากคุณต้องการให้วัตถุวันที่ซึ่งมีการปรับเขตข้อมูลสำหรับ UTC คุณสามารถทำได้เช่นนี้ด้วยJoda Time :

import org.joda.time.DateTimeZone;
import java.util.Date;

...

Date local = new Date();
System.out.println("Local: " + local);
DateTimeZone zone = DateTimeZone.getDefault();
long utc = zone.convertLocalToUTC(local.getTime(), false);
System.out.println("UTC: " + new Date(utc));

1
คุณทำงานหนักเกินไป Joda-Timeสามารถทำได้ในรหัสบรรทัดเดียว ดูคำตอบของฉันในคำถามนี้ เรียกใช้.toDateTimeเมธอดและส่งค่าคงที่สำหรับโซนเวลา UTC
Basil Bourque

1
DateTime utcDate = new DateTime (). toDateTime (DateTimeZone.UTC)
Maciej Miklas

6

คุณสามารถใช้ได้:

Calendar aGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

จากนั้นการดำเนินการทั้งหมดที่ดำเนินการโดยใช้วัตถุ aGMTCalendar จะดำเนินการกับเขตเวลา GMT และจะไม่มีการปรับเวลาตามฤดูกาลหรือการชดเชยแบบคงที่ ฉันคิดว่าผู้โพสต์ก่อนหน้านี้ถูกต้องว่าวัตถุ Date () ส่งคืน GMT เสมอไม่ใช่จนกว่าคุณจะทำอะไรกับวัตถุวันที่ที่ได้รับการแปลงเป็นเขตเวลาท้องถิ่น


6
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(dateFormatGmt.format(date));

โปรดเพิ่มคำอธิบายลงในคำตอบของคุณแตกต่างจากคำตอบอื่น ๆ อีกมากมาย?
akjoshi

วิธีนี้ทำให้เวลาขึ้นอยู่กับปฏิทินของอุปกรณ์?
อาร์โนลด์บราวน์

6

คุณสามารถใช้สิ่งนี้ได้โดยตรง

SimpleDateFormat dateFormatGmt = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(dateFormatGmt.format(new Date())+"");

5

ด้วย:

Calendar cal = Calendar.getInstance();

จากนั้นให้calมีวันที่และเวลาปัจจุบัน
คุณสามารถรับวันที่และเวลาปัจจุบันของเขตเวลาด้วย:

Calendar cal2 = Calendar.getInstance(TimeZone.getTimeZone("GMT-2"));

คุณสามารถถามcal.get(Calendar.DATE);หรือปฏิทินอื่น ๆ คงที่เกี่ยวกับรายละเอียดอื่น ๆ
Date and Timestamp เลิกใช้แล้วใน Java คลาสของปฏิทินไม่ใช่


6
วิธีการและตัวสร้างบางอย่างของ Date and Timestamp นั้นถูกคัดค้าน แต่ตัวคลาสนั้นไม่
Powerlord

5

นี่คือข้อเสนอแนะอื่น ๆ เพื่อรับวัตถุเวลาประทับ GMT:

import java.sql.Timestamp;
import java.util.Calendar;

...

private static Timestamp getGMT() {
   Calendar cal = Calendar.getInstance();
   return new Timestamp(cal.getTimeInMillis()
                       -cal.get(Calendar.ZONE_OFFSET)
                       -cal.get(Calendar.DST_OFFSET));
}

5

นี่เป็นอีกวิธีในการรับเวลา GMT ในรูปแบบ String

String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss z" ;
final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String dateTimeString =  sdf.format(new Date());

5

นี่คือการใช้งาน toUTC ของฉัน:

    public static Date toUTC(Date date){
    long datems = date.getTime();
    long timezoneoffset = TimeZone.getDefault().getOffset(datems);
    datems -= timezoneoffset;
    return new Date(datems);
}

อาจมีหลายวิธีในการปรับปรุง แต่ก็ใช้งานได้สำหรับฉัน


3

โค้ดตัวอย่างเพื่อแสดงเวลาของระบบในเขตเวลาและรูปแบบเฉพาะ

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class TimZoneTest {
    public static void main (String[] args){
        //<GMT><+/-><hour>:<minutes>
        // Any screw up in this format, timezone defaults to GMT QUIETLY. So test your format a few times.

        System.out.println(my_time_in("GMT-5:00", "MM/dd/yyyy HH:mm:ss") );
        System.out.println(my_time_in("GMT+5:30", "'at' HH:mm a z 'on' MM/dd/yyyy"));

        System.out.println("---------------------------------------------");
        // Alternate format 
        System.out.println(my_time_in("America/Los_Angeles", "'at' HH:mm a z 'on' MM/dd/yyyy") );
        System.out.println(my_time_in("America/Buenos_Aires", "'at' HH:mm a z 'on' MM/dd/yyyy") );


    }

    public static String my_time_in(String target_time_zone, String format){
        TimeZone tz = TimeZone.getTimeZone(target_time_zone);
        Date date = Calendar.getInstance().getTime();
        SimpleDateFormat date_format_gmt = new SimpleDateFormat(format);
        date_format_gmt.setTimeZone(tz);
        return date_format_gmt.format(date);
    }

}

เอาท์พุต

10/08/2011 21:07:21
at 07:37 AM GMT+05:30 on 10/09/2011
at 19:07 PM PDT on 10/08/2011
at 23:07 PM ART on 10/08/2011

3

เพียงเพื่อทำให้ง่ายขึ้นเพื่อสร้าง a DateในUTCคุณสามารถใช้Calendar:

Calendar.getInstance(TimeZone.getTimeZone("UTC"));

ซึ่งจะสร้างอินสแตนซ์ใหม่สำหรับCalendarการใช้ TimeZone"UTC"

หากคุณต้องการวัตถุจากปฏิทินที่คุณก็สามารถใช้DategetTime()


5
การเรียกใช้ getTime () ทำให้เกิดการสูญเสียข้อมูลโซนเวลาและส่งคืนเวลาท้องถิ่น
RealCasually

3

การแปลง DateTime ปัจจุบันใน UTC:

DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

DateTimeZone dateTimeZone = DateTimeZone.getDefault(); //Default Time Zone

DateTime currDateTime = new DateTime(); //Current DateTime

long utcTime = dateTimeZone.convertLocalToUTC(currDateTime .getMillis(), false);

String currTime = formatter.print(utcTime); //UTC time converted to string from long in format of formatter

currDateTime = formatter.parseDateTime(currTime); //Converted to DateTime in UTC

1
คุณทำงานที่นี่มากเกินไป (a) รูปแบบการกระจายรูปแบบที่คุณกำหนดได้ถูกสร้างไว้แล้วใน DateTime โดยค่าเริ่มต้น เพียงแค่เรียกtoStringใช้ DateTime เพื่อรับรูปแบบสตริงISO 8601 (b) แปลงรหัสมากเกินไประหว่างเขตเวลา เพียงเรียก "toDateTime" และผ่านวัตถุเขตเวลา myDateTime.toDateTime( DateTimeZone.UTC )เช่นนี้ สำหรับโซนเวลาที่เฉพาะเจาะจง instantiate และผ่านวัตถุโซนเวลาขึ้นอยู่กับชื่อที่เหมาะสมmyDateTime.toDateTime( DateTimeZone.forID( "Asia/Tehran" ) )โทร
Basil Bourque

2

สิ่งนี้ใช้งานได้สำหรับฉันส่งคืนการประทับเวลาใน GMT!

    Date currDate;
    SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
    dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
    SimpleDateFormat dateFormatLocal = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");

    long currTime = 0;
    try {

        currDate = dateFormatLocal.parse( dateFormatGmt.format(new Date()) );
        currTime = currDate.getTime();
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

2

ใช้คลาสนี้เพื่อรับเวลา UTC ที่ถูกต้องจากเซิร์ฟเวอร์ NTP ออนไลน์:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;


class NTP_UTC_Time
{
private static final String TAG = "SntpClient";

private static final int RECEIVE_TIME_OFFSET = 32;
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;

private static final int NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_VERSION = 3;

// Number of seconds between Jan 1, 1900 and Jan 1, 1970
// 70 years plus 17 leap days
private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;

private long mNtpTime;

public boolean requestTime(String host, int timeout) {
    try {
        DatagramSocket socket = new DatagramSocket();
        socket.setSoTimeout(timeout);
        InetAddress address = InetAddress.getByName(host);
        byte[] buffer = new byte[NTP_PACKET_SIZE];
        DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);

        buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);

        writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET);

        socket.send(request);

        // read the response
        DatagramPacket response = new DatagramPacket(buffer, buffer.length);
        socket.receive(response);          
        socket.close();

        mNtpTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);            
    } catch (Exception e) {
      //  if (Config.LOGD) Log.d(TAG, "request time failed: " + e);
        return false;
    }

    return true;
}


public long getNtpTime() {
    return mNtpTime;
}


/**
 * Reads an unsigned 32 bit big endian number from the given offset in the buffer.
 */
private long read32(byte[] buffer, int offset) {
    byte b0 = buffer[offset];
    byte b1 = buffer[offset+1];
    byte b2 = buffer[offset+2];
    byte b3 = buffer[offset+3];

    // convert signed bytes to unsigned values
    int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
    int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
    int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
    int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);

    return ((long)i0 << 24) + ((long)i1 << 16) + ((long)i2 << 8) + (long)i3;
}

/**
 * Reads the NTP time stamp at the given offset in the buffer and returns 
 * it as a system time (milliseconds since January 1, 1970).
 */    
private long readTimeStamp(byte[] buffer, int offset) {
    long seconds = read32(buffer, offset);
    long fraction = read32(buffer, offset + 4);
    return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);        
}

/**
 * Writes 0 as NTP starttime stamp in the buffer. --> Then NTP returns Time OFFSET since 1900
 */    
private void writeTimeStamp(byte[] buffer, int offset) {        
    int ofs =  offset++;

    for (int i=ofs;i<(ofs+8);i++)
      buffer[i] = (byte)(0);             
}

}

และใช้กับ:

        long now = 0;

        NTP_UTC_Time client = new NTP_UTC_Time();

        if (client.requestTime("pool.ntp.org", 2000)) {              
          now = client.getNtpTime();
        }

หากคุณต้องการเวลา UTC "ตอนนี้" เป็นฟังก์ชั่นการใช้ DateTimeString:

private String get_UTC_Datetime_from_timestamp(long timeStamp){

    try{

        Calendar cal = Calendar.getInstance();
        TimeZone tz = cal.getTimeZone();

        int tzt = tz.getOffset(System.currentTimeMillis());

        timeStamp -= tzt;

        // DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.getDefault());
        DateFormat sdf = new SimpleDateFormat();
        Date netDate = (new Date(timeStamp));
        return sdf.format(netDate);
    }
    catch(Exception ex){
        return "";
     }
    } 

และใช้กับ:

String UTC_DateTime = get_UTC_Datetime_from_timestamp(now);

ในบรรทัดเดียว <br/> <pre> <code> ปฏิทิน utcTime = Calendar.getInstance (). เพิ่ม (Calendar.MILLISECOND, -time.getTimeZone (). getOffset (time.getTimeInMillis ()); </pre> / code>
Harun

1
ใช่ แต่สิ่งนี้จะเรียกเวลาท้องถิ่นของอุปกรณ์ซึ่งสามารถเปลี่ยน manualy จากผู้ใช้เป็น DateTime ที่ผิดพลาดได้
Ingo


1

ที่จะทำให้มันง่าย วัตถุปฏิทินเก็บข้อมูลเกี่ยวกับเขตเวลา แต่เมื่อคุณทำการ cal.getTime () ข้อมูลเขตเวลาจะหายไป ดังนั้นสำหรับการแปลงเขตเวลาฉันจะแนะนำให้ใช้คลาส DateFormat ...


1

นี่คือการดำเนินการของฉัน:

public static String GetCurrentTimeStamp()
{
    Calendar cal=Calendar.getInstance();
    long offset = cal.getTimeZone().getOffset(System.currentTimeMillis());//if you want in UTC else remove it .
    return new java.sql.Timestamp(System.currentTimeMillis()+offset).toString();    
}

1

หากคุณต้องการหลีกเลี่ยงการแยกวิเคราะห์วันที่และต้องการเวลาประทับใน GMT คุณสามารถใช้:

final Date gmt = new Timestamp(System.currentTimeMillis()
            - Calendar.getInstance().getTimeZone()
                    .getOffset(System.currentTimeMillis()));

0

หากคุณใช้เวลา joda และต้องการเวลาปัจจุบันเป็นมิลลิวินาทีโดยไม่มีออฟเซ็ตท้องถิ่นของคุณคุณสามารถใช้สิ่งนี้:

long instant = DateTimeZone.UTC.getMillisKeepLocal(DateTimeZone.getDefault(), System.currentTimeMillis());

0
public class CurrentUtcDate 
{
    public static void main(String[] args) {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
        System.out.println("UTC Time is: " + dateFormat.format(date));
    }
}

เอาท์พุท:

UTC Time is: 22-01-2018 13:14:35

คุณสามารถเปลี่ยนรูปแบบวันที่ได้ตามต้องการ


1
SimpleDateFormatกรุณาอย่าสอนให้คนหนุ่มสาวที่จะใช้ล้าสมัยนานและลำบากฉาวโฉ่ วันนี้เรามีมากดีกว่าในการjava.timeที่ทันสมัย Java วันที่และเวลา API คุณให้อะไรที่ไม่ได้อยู่ในคำตอบของ Dan, Antonio และคนอื่น ๆ ?
Ole VV

2
(a) คำตอบนี้เพิ่มมูลค่าให้กับคำตอบที่มีอยู่หลายสิบข้อได้อย่างไร (b) คลาสที่มีปัญหาที่ใช้ในที่นี้ถูกแทนที่เมื่อหลายปีก่อนโดยคลาสjava.time ที่ทันสมัย แนะนำให้ใช้ในปี 2561 เป็นคำแนะนำที่ไม่ดี
Basil Bourque

0

ใช้แพ็คเกจ java.time และรวมรหัสด้านล่าง -

ZonedDateTime now = ZonedDateTime.now( ZoneOffset.UTC );

หรือ

LocalDateTime now2 = LocalDateTime.now( ZoneOffset.UTC );

ขึ้นอยู่กับความต้องการใช้งานของคุณ


(A) ถ้าใช้ชดเชย ( ZoneOffset) มากกว่าโซนเวลา ( ZoneId) ที่มีความเหมาะสมมากกว่าOffsetDateTime ZonedDateTime(B) LocalDateTimeไม่ควรใช้สำหรับการจับภาพช่วงเวลาปัจจุบันเนื่องจากไม่มีแนวคิดของเขตเวลาหรือออฟเซ็ตจาก UTC (C) คำตอบที่มีอยู่ก่อนอื่นได้ครอบคลุมเนื้อหานี้และทำงานได้ดีขึ้น ฉันไม่เห็นว่าคำตอบนี้เพิ่มคุณค่าอย่างไร
Basil Bourque
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.