Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu về Clock class thuộc package java.time trong java. Để dễ hiểu thì các bạn cứ xem clock là một cái đồng hồ, với các múi giờ khác nhau thì những cái đồng hồ này sẽ có giá trị khác nhau.
Clock class là một abstract class vì vậy chúng ta không thể khởi tạo nó, tuy nhiên chúng ta có thể sử dụng một số static method được định nghĩa trong nó.
Hầu hết các Date API đều cung cấp các method để thao tác với ngày giờ, nên việc sử dụng Clock là optional. Sử dụng Clock khi bạn muốn thay đổi đồng hồ mặc định trong hệ thống.
Clock class thường được sử dụng trong các mục đích kiểm thử tốc độ của một đoạn chương trình. Từ đó chúng ta có thể biết được chính xác ở đâu trong chương trình có tốc độ thực thi chậm và có kế hoặc để tối ưu hoá chúng.
Clock cũng có thể thay thế System.currentTimeMillis() và TimeZone.getDefault();
Các method trong Clock
Như đã đề cập ở trên thì Clock là một abstract method vậy nên dưới đây là các static method của Clock class và các instance method của các child class của Clock. Chúng ta sẽ cùng nhau tìm hiểu xem các sử dụng của chúng nha.
systemDefaultZone()
systemDefaultZone() trả về một instance của Clock sử dụng múi giờ mặc định của hệ thống.
// Syntax public static Clock systemDefaultZone() // Example Clock clock = Clock.systemDefaultZone(); System.out.println(clock.getZone()); // Asia/Ho_Chi_Minh System.out.println(clock.millis()); // 1577679681906
Note:
- Kết quả có thể khác nhau khi chạy trên các máy khác nhau tuỳ thuộc vào múi giờ mà máy các bạn đang sử dụng.
- Bên trong systemDefaultZone() khởi tạo một instance của ClockSystem class thừa kế từ Clock.
instant()
Trả về instant – thời gian hiện tại của clock.
// Syntax public abstract Instant instant(); // Example Clock clock = Clock.systemDefaultZone(); Instant instant = clock.instant(); System.out.println(instant); // 2019-12-30T05:26:44.897Z
systemUTC()
systemUTC() trả về một instance của Clock, khi bạn cần sử dụng đến Instant mà không cần ngày hay thời gian thì nên sử dụng nó thay thế cho systemDefaultZone().
// Syntax public static Clock systemUTC() // Example Clock clock = Clock.systemUTC(); System.out.println(clock.getZone()); // "Z"
system(ZoneId zone)
system() Trả về một instance clock với múi giờ được chỉ định.
// Syntax public static Clock system(ZoneId zone) // Example Clock clock = Clock.system(ZoneId.of("Europe/Paris")); System.out.println(LocalDateTime.now(clock)); // 2019-12-30T07:06:16.552
millis()
millis() trả về số miliseconds của instance clock.
// Syntax public long millis() // Example Clock clock = Clock.systemDefaultZone(); System.out.println(clock.millis()); // 1577686459704
millis() tương đương với System.currentTimeMills().
Clock clock = Clock.systemDefaultZone(); System.out.println(clock.millis()); // 1577686602462 System.out.println(System.currentTimeMillis()); //1577686602462
Note: Số miliseconds là hằng số và luôn giống nhau ở bất kỳ múi giờ nào.
Clock clock = Clock.system(ZoneId.of("Europe/Paris")); System.out.println(clock.millis()); // 1577686785161 System.out.println(System.currentTimeMillis()); // 1577686785161
offset(Clock baseClock, Duration offsetDuration)
offet() method trả về một instance của Clock với Instant bằng tổng của Instant của baseClock với một khoảng thời gian offsetDuration từ tham số truyền vào.
Nếu offsetDuration âm chúng ta sẽ một clock quay trở về thời gian trong quá khứ, nếu offsetDuration chúng ta sẽ có clock thời gian trong tương lai. offset() thường được sử dụng để tính thời gian trong tương lai hoặc quá khứ.
// Syntax public static Clock offset(Clock baseClock, Duration offsetDuration) // Example Clock baseClock = Clock.systemDefaultZone(); Clock pastClock = Clock.offset(baseClock, Duration.ofMillis(-10000)); System.out.println(baseClock.millis() - pastClock.millis()); //prints 10000 Clock futureClock = Clock.offset(baseClock, Duration.ofDays(1)); System.out.println(futureClock.millis() - baseClock.millis()); //prints 86400000
tick(Clock baseClock, Duration tickDuration)
tick() trả về một instance Clock từ baseClock có instant cắt ngắn gần đến lần xuất hiện gần nhất của baseClock với khoảng tickDuration.
// Syntax public static Clock tick(Clock baseClock, Duration tickDuration) // Example import java.time.*; class Main { public static void main(String[] args) { Clock baseClock = Clock.systemDefaultZone(); Clock tickClock = Clock.tick(baseClock, Duration.ofMillis((100))); for (int i = 1; i <= 3; i++) { System.out.println("-----" + i + "-----"); System.out.println("Base: " + baseClock.instant()); System.out.println("Tick: " + tickClock.instant()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Output:
—–1—–
Base: 2019-12-30T12:12:57.835Z
Tick: 2019-12-30T12:12:57.800Z
—–2—–
Base: 2019-12-30T12:13:00.850Z
Tick: 2019-12-30T12:13:00.800Z
—–3—–
Base: 2019-12-30T12:13:03.852Z
Tick: 2019-12-30T12:13:03.800Z
Các bạn thấy thời gian được làm tròn đến 100milis.
Note:
- Nếu tickDuration của chúng ta là 1milis thì chúng ta có thể dùng tickMillis() và 1 phút thì sử dụng tickMinutes().
- tickDuration phải là giá trị dương.
fixed(Instant fixedInstant, ZonedId zone)
fixed() trả về một instance của Clock và instance này luôn trả về Instant có cùng giá trị.
// Syntax public static Clock fixed(Instant fixedInstant, ZoneId zone) // Example import java.time.*; class Main { public static void main(String[] args) throws InterruptedException { Clock fixedClock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); System.out.println(fixedClock); // FixedClock[2019-12-30T09:34:15.343Z,Asia/Ho_Chi_Minh] System.out.println(fixedClock.instant()); // 2019-12-30T09:34:15.343Z Thread.sleep(1000); System.out.println(fixedClock.instant()); // 2019-12-30T09:34:15.343Z } }
Một số cách áp dụng Clock
Đo thời gian thực thi
Khi ứng dụng của bạn chạy quá trình và bạn muốn nó chạy nhanh hơn. Sau khi chúng ta chạy chương trình và xác định những đoạn code có liên qua thì việc tiếp theo là chúng ta phải đo xem những đoạn code đó thực thi trong bao lâu và sau khi tối ưu thì nó sẽ chạy trong bao lâu để đánh giá độ hiểu quả.
Ví dụ tính tổng các số nguyên từ 0 đến 1000000000
import java.time.*; class Main { public static void main(String[] args) { long before = Clock.systemDefaultZone().millis(); long sum = 0; for(int i = 0; i < 1000000000; i++) sum+=i; System.out.println("Sum: " + sum); long after = Clock.systemDefaultZone().millis(); System.out.println("Thoi gian thu thi: " + (after - before)); } }
Output:
Sum: 499999999500000000
Thoi gian thu thi: 346
Đồng hồ đa quốc gia
Nếu bạn đã từng thấy các đồng hồ điện tử hiện đại ngày nay thì ngoài hiển thị giờ của Việt Nam thì nó còn có giờ của những thành phố khác trên thế giới như là Paris, Los Angeles etc. Hôm nay chúng ta sẽ làm thử đồng hiển thị giờ của 4 thành phố lớn: HCM, Paris, Los Angeles, Darwin nhưng với giao diện console, nếu các bạn muốn phát triển thêm thì có thể sử dụng thêm một số package hỗ trợ làm UI của java nhé.
Trong ví dụ dưới đây ngoài sử dụng Clock class thì mình còn sử dụng thêm LocalDateTime để hỗ trợ chuyển sang ngày giờ cho các bạn dễ nhìn.
import java.time.*; class Main { public static void main(String[] args) throws InterruptedException { Clock sys = Clock.systemDefaultZone(); Clock clockPr = Clock.system(ZoneId.of("Europe/Paris")); Clock clockArLos = Clock.system(ZoneId.of("America/Los_Angeles")); Clock clockAuDar = Clock.system(ZoneId.of("Australia/Darwin")); while (true) { Thread.sleep(1000); LocalDateTime dateTimeSys = LocalDateTime.now(sys); System.out.println("System: " + dateTimeSys.getHour() + ":" + dateTimeSys.getMinute() + ":" + dateTimeSys.getSecond()); LocalDateTime dateTimePr = LocalDateTime.now(clockPr); System.out.println("Paris: " + dateTimePr.getHour() + ":" + dateTimePr.getMinute() + ":" + dateTimePr.getSecond()); LocalDateTime dateTimeLos = LocalDateTime.now(clockArLos); System.out.println("Los Angeles: " + dateTimeLos.getHour() + ":" + dateTimeLos.getMinute() + ":" + dateTimeLos.getSecond()); LocalDateTime dateTimeDa = LocalDateTime.now(clockAuDar); System.out.println("Darwin: " + dateTimeDa.getHour() + ":" + dateTimeDa.getMinute() + ":" + dateTimeDa.getSecond()); System.out.println("---------------------------"); } } }
Kết luận
Clock class cho đến bây giờ vẫn còn những tính năng riêng của nó tuy nhiên với một người làm software như mình thì ít khi dùng đến, ngoài ra cũng có rất nhiều class khác hỗ trợ Date & Time trong java. Cho đến gần đây thì trong team mới sử dụng nó nhiều để review lại xem chỗ nào đang chạy chậm và tiến hành tối ưu hoá, sau đó tiến hành đo lại để kiểm tra kết quả.