วิธีรับมิลลิวินาทีจาก LocalDateTime ใน Java 8


285

ผมสงสัยว่าถ้ามีวิธีที่จะได้รับในปัจจุบันมิลลิวินาทีตั้งแต่ 1970/01/01 (ยุค) โดยใช้ใหม่LocalDate, LocalTimeหรือLocalDateTimeชั้นเรียนของ Java 8

วิธีที่ทราบอยู่ด้านล่าง:

long currentMilliseconds = new Date().getTime();

หรือ

long currentMilliseconds = System.currentTimeMillis();

6
มีอะไรผิดปกติกับSystem.currentTimeMillis()?
Dawood ibn Kareem

16
@DavidWallace เขากำลังพยายามหาเวลาของวันที่ไม่ใช่เวลาปัจจุบันใช่ไหม
Anubian Noob

2
"... วิธีหามิลลิวินาทีปัจจุบัน ... "
Dawood ibn Kareem

มิลลิวินาทีนับตั้งแต่ 1-1-1970 ฉันหลงทางถ้ามีวิธีการทำให้พวกเขาใช้คลาสใหม่ของ Java 8 LocalDate, LocalTime และ LocalDateTime ทำให้ฉันไม่พบมัน
George Siggouroglou

1
ความเข้าใจของฉันเกี่ยวกับจุดประสงค์สำหรับชั้นเรียนเหล่านั้นคือการทำความเข้าใจ "เวลาที่เน้นมนุษย์" และcurrentTimeMillisจะไม่เกี่ยวข้องในบริบทนั้น คิดว่าปฏิทิน + นาฬิกาแขวนมีความแม่นยำดีมากและไม่ต้องกังวลกับโซนเวลาและท้องที่ ดังนั้นจึงไม่มีทางที่จะกลับไปที่ "เวลา UTC" จาก LocalTime
Gus

คำตอบ:


325

ฉันไม่แน่ใจว่าคุณหมายถึงอะไรโดย "มิลลิวินาทีปัจจุบัน" แต่ฉันจะถือว่ามันเป็นจำนวนมิลลิวินาทีนับตั้งแต่ "ยุค" คือเที่ยงคืนวันที่ 1 มกราคม 1970 UTC

หากคุณต้องการที่จะหาจำนวนมิลลิวินาทีตั้งแต่ยุคที่ตอนนี้แล้วใช้System.currentTimeMillis()เป็นAnubian Noob ได้ชี้ให้เห็น ถ้าเป็นเช่นนั้นไม่มีเหตุผลที่จะใช้ java.time APIs ใด ๆ ในการทำสิ่งนี้

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

สมมติว่าคุณมีสิ่งLocalDateTimeนี้:

LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16);

ZonedDateTimeคุณจำเป็นต้องใช้ข้อมูลโซนเวลาให้ ฉันอยู่ในเขตเวลาเดียวกันกับลอสแองเจลิสดังนั้นฉันจะทำสิ่งนี้:

ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles"));

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

อย่างไรก็ตามหากคุณได้รับที่ถูกต้องZonedDateTimeคุณสามารถแปลงเป็นจำนวนมิลลิวินาทีนับตั้งแต่ยุคเช่น:

long millis = zdt.toInstant().toEpochMilli();

5
โปรดทราบว่าZonedDateTimeแล้วมีgetEpochSecondวิธี (ผ่านChronoZonedDateTime เริ่มต้น ) Instantไม่มีความจำเป็นในการ
mabi

14
แน่นอนถ้าทั้งหมดที่คุณต้องการคือไม่กี่วินาทีไม่ใช่มิลลิวินาที
Stuart Marks

1
อาดีผมก็ไม่แน่ชัด: ZonedDateTimeยังมีInstants getNanoวิธีดังนั้นคุณจะไม่สามารถที่จะเพียงแค่เปลี่ยนinstที่มีzdtในตัวอย่างของคุณหรือไม่
mabi

18
หลีกเลี่ยงการคณิตศาสตร์ในนาโนโดยใช้ zdt.get (ChronoField.MILLI_OF_SECOND) หลีกเลี่ยงคณิตศาสตร์ทั้งหมดโดยใช้ zdt.toInstant (). toEpochMilli ()
JodaStephen

1
อย่างไรก็ตามเนื่องจากคุณและ @walen ได้แสดงความคิดเห็นแล้วฉันจึงตัดสินใจลบข้อความต้นฉบับของฉันตอนนี้เพื่อหลีกเลี่ยงการทำให้ผู้อื่นเข้าใจผิด
ต่อ Lundberg

81

สิ่งที่ฉันทำฉันไม่ได้ระบุเขตเวลาคือ

System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("ctm " + System.currentTimeMillis());

จะช่วยให้

ldt 1424812121078 
ctm 1424812121281

คุณสามารถเห็นตัวเลขเหมือนกันยกเว้นเวลาดำเนินการเล็กน้อย

ในกรณีที่คุณไม่ชอบ System.currentTimeMillis ให้ใช้ Instant.now().toEpochMilli()


3
ไม่ยุคเมื่อเทียบกับ UTC แต่คุณได้รับเวลาปัจจุบันจากโซนท้องถิ่นของคุณ
ราฟาเอล Membrives

2
@ ChristofferHammarströmจำนวนมิลลิวินาทีที่ผ่านไปเนื่องจากยุคนั้นเป็นอิสระจากเขตเวลา จำนวนมิลลิวินาทีเท่ากันไม่ว่าคุณจะเรียกมันว่าเวลาใดของวัน ผลลัพธ์ทั้งสองแตกต่างกันเนื่องจากเครื่องของไบรอันใช้เวลา 203 มิลลิวินาทีในการดำเนินการคำสั่งที่สอง
Fletch

การใช้ UTC เมื่อผู้ใช้อาจอยู่ในเขตเวลาอื่น
GilbertS

2
@GilbertS คุณไม่ควรใช้รหัสที่แน่นอนนี้ใช้ API ตามที่ตั้งใจไว้ วันที่และเวลาควรเป็น UTC เมื่อเก็บไว้ในคอมพิวเตอร์หรือส่งไปยังผู้ใช้รายอื่น โดยทั่วไปควรจะแสดงให้ผู้ใช้เห็นว่าเป็นวันที่เวลาท้องถิ่นโดยใช้การตั้งค่าเขตเวลาของตนเอง
ไบรอัน

20

ในการหลีกเลี่ยง ZoneId คุณสามารถทำได้:

LocalDateTime date = LocalDateTime.of(1970, 1, 1, 0, 0);

System.out.println("Initial Epoch (TimeInMillis): " + date.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());

ได้รับ 0 เป็นค่าที่เหมาะสม!


8
ZoneOffset.ofTotalSeconds(0)มันเป็นเช่นเดียวกับZoneOffset.UTC
Anton Novopashin

1
ใช่ฉันเป็น upvoting @ ความคิดเห็น AntonNovopashin ของ เนื่องจากคุณจำเป็น UTC คุณกำลังดี (คุณอาจต้องการที่จะพูดถึงว่าในคำตอบ) BTW ZoneOffsetเป็น subclass ของZoneIdดังนั้นฉันจะไม่พูดว่าคุณได้หลีกเลี่ยงมัน แต่ตราบใดที่คุณมีความสุข ...
Ole VV

ความคิดเห็นแรกของฉันเป็นบิตรุนแรง แต่ไม่ได้หมายความว่าเป็นที่น่ารังเกียจ คุณทำผิดกฎหมาย ฉันขอโทษ. ฉันได้ลบมัน อนุญาตให้ฉันถามอีกทางหนึ่ง: เหตุผลของเราที่ต้องการหลีกเลี่ยงZoneIdอะไร
Ole VV

@ OleV.V สามารถใช้ UTC ได้หรือไม่ ไม่ได้มีไว้สำหรับคนที่อาศัยอยู่ในเขตเวลา UTC เท่านั้น
GilbertS

1
@GilbertS ฉันไม่คิดว่ามีใครอาศัยอยู่ในเขตเวลา UTC แนะนำให้ใช้ UTC สำหรับเวลาที่ใช้ข้ามเขตเวลาเป็นแนวทางปฏิบัติที่ดี ดูตัวอย่างJava ปฏิบัติที่ดีที่สุดสำหรับวันที่การจัดการ / จัดเก็บสำหรับผู้ใช้ที่มีความหลากหลายทางภูมิศาสตร์ หรือฉันอาจไม่เข้าใจคำถามของคุณ?
Ole VV

15

ตั้งแต่ Java 8 คุณสามารถโทรjava.time.Instant.toEpochMilli()ได้

ตัวอย่างเช่นการโทร

final long currentTimeJava8 = Instant.now().toEpochMilli();

ให้ผลลัพธ์เหมือนกับคุณ

final long currentTimeJava1 = System.currentTimeMillis();

1
"ช่วยให้คุณมีผลเช่นเดียวกับ" ... แต่ใช้พลังงาน CPU มากขึ้นและเน้นการเก็บขยะมากขึ้น
VasiliNovikov

1
ผมต้องการที่จะเห็นข้างต้นวัด (โดยเฉพาะอย่างยิ่งสำหรับการใช้งานปกติ - เช่นไม่ได้สำหรับการประยุกต์ใช้จริงเวลาที่สำคัญประสิทธิภาพการทำงานบางอย่าง ... )
ไบรอัน Agnew

11

คุณสามารถใช้java.sql.Timestampเพื่อรับมิลลิวินาที

LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);

คุณไม่สนใจความต้องการที่สำคัญสำหรับเขตเวลา ผมไม่แนะนำให้ทำอย่างนี้ อีกทั้งTimestampคลาสนั้นล้าสมัยไปแล้วและเต็มไปด้วยปัญหาการออกแบบดังนั้นฉันจึงควรหลีกเลี่ยงโดยเฉพาะเมื่อเราสามารถใช้คลาสได้java.timeเช่นLocalDateTimeกัน
Ole VV

@ OleV.V แค่อยากรู้เกี่ยวกับปัญหาการออกแบบของTimestampคุณสามารถแบ่งปันบทความบางอย่างกับที่? มันช่วยให้ฉันหลีกเลี่ยงการใช้Timestampรหัสของฉันได้เช่นกัน ขอบคุณ!
Nalam

1
แค่สั้น ๆ ก็นำมาใช้เป็น subclass ของแต่มักจะไม่สามารถจัดการได้เป็นDate Dateวิธีการส่วนใหญ่ที่สืบทอดมาจากDateและหนึ่งตัวสร้างถูกคัดค้าน toStringวิธีการของมันใช้เขตเวลาของ JVM ซึ่งสร้างความสับสนให้มากมายเนื่องจากTimestampมีการพิมพ์เดียวกันบนคอมพิวเตอร์ที่แตกต่างกัน ( ตัวอย่าง )
Ole VV

นี่คือที่สมบูรณ์แบบสำหรับการทดสอบหน่วย เพียงแทนที่ตอนนี้ด้วยLocalDate.of(year, month, day)
G_V

นี่ควรเป็นคำตอบที่ได้รับการยอมรับในการแก้ปัญหาค่า "always UTC"
LeYAUable

9

ที่จะได้รับเวลาปัจจุบันในหน่วยมิลลิวินาที (ตั้งแต่ยุค) System.currentTimeMillis()การใช้งาน


3

หากคุณมีนาฬิกา Java 8 คุณสามารถใช้clock.millis()(แม้ว่าจะแนะนำให้คุณใช้clock.instant()เพื่อรับ Java 8 ทันทีเนื่องจากแม่นยำยิ่งขึ้น)

ทำไมคุณถึงใช้นาฬิกา Java 8 ดังนั้นในกรอบ DI ของคุณคุณสามารถสร้าง Clock bean:

@Bean
public Clock getClock() {
    return Clock.systemUTC();
}

และจากการทดสอบคุณสามารถเยาะเย้ยมันได้อย่างง่ายดาย:

@MockBean private Clock clock;

หรือคุณมีถั่วอื่น:

@Bean
public Clock getClock() {
    return Clock.fixed(instant, zone);
}

ซึ่งจะช่วยในการทดสอบที่ยืนยันวันที่และเวลาอย่างมากมาย


1
  default LocalDateTime getDateFromLong(long timestamp) {
    try {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
    } catch (DateTimeException tdException) {
      //  throw new 
    }
}

default Long getLongFromDateTime(LocalDateTime dateTime) {
    return dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli();
}

0

ทำไมไม่มีใครพูดถึงวิธีการLocalDateTime.toEpochSecond():

LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);

ดูเหมือนว่าจะสั้นกว่าที่คำตอบหลายคำแนะนำข้างต้น ...


นี่คือสิ่งที่ฉันกำลังมองหา คำตอบที่ได้รับการยอมรับนั้นคือการมอบกำลังใจให้ฉัน
Brill Pappin สุดยอด

ยอมรับเฉพาะใน API 26: {
Brill Pappin

1
เพราะมันให้เวลาเพียงไม่กี่วินาที มันแปลกว่าไม่มีtoEpochMilliวิธีนำเข้าบัญชีจริงที่ว่าคุณสามารถระบุแม้นาโนวินาทีใน LocalDateTime: LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond)มีวิธีการ
izogfif
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.