นากกายต้นฉบับเรียงลูกปัดเหตุการณ์ลงช่องนาทีบนหน้าปัดวงกลมที่มีเส้นตัดชัด

Java Instant.truncatedTo: จัด event ลง bucket นาทีโดยไม่ปัดผิดเขตเวลา

พี่โชว์Engineering

dashboard ที่นับ event ต่อนาทีต้องตัดเวลา 10:02:59 ลงช่อง 10:02 ถ้าปัดเป็น 10:03 กราฟจะคลาดและ alert อาจยิงผิดช่วงครับ Instant.truncatedTo คืนสำเนาเวลาที่ตั้งหน่วยย่อยกว่าให้เป็นศูนย์ เหมือนวางลูกปัดทุกเม็ดที่เกิดในนาทีเดียวลงกล่องเดียวกัน โดยไม่แก้ event ต้นฉบับ

Instant คือจุดเวลาบน timeline แบบ UTC จึงเหมาะเป็น key สำหรับ bucket นาทีหรือชั่วโมงทั่วระบบ หากต้องสรุป วันที่ตามกรุงเทพฯ ควรแปลงด้วย ZoneId ก่อนหา LocalDate ไม่ใช่ truncate Instant เป็นวันแล้วเรียกว่าวันไทย เพราะขอบวัน UTC ต่างจากขอบวันท้องถิ่น

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;

public class Main {
    public static void main(String[] args) {
        Instant event = Instant.parse("2026-09-20T17:02:59.999Z");
        Instant minute = event.truncatedTo(ChronoUnit.MINUTES);
        assert minute.equals(Instant.parse("2026-09-20T17:02:00Z"));
        assert event.equals(Instant.parse("2026-09-20T17:02:59.999Z"));

        LocalDate bangkokDay = event.atZone(ZoneId.of("Asia/Bangkok")).toLocalDate();
        assert bangkokDay.equals(LocalDate.of(2026, 9, 21));
        assert !bangkokDay.equals(event.atZone(ZoneId.of("UTC")).toLocalDate());
        System.out.println("Instant bucket tests passed");
    }
}

เลือก bucket ตามคำถามธุรกิจ

ถ้าถาม “มี request กี่ครั้งในนาทีเดียวกันทั่วโลก” ให้ key เป็น Instant.truncatedTo(MINUTES) แล้วแสดง label ใน zone ที่ผู้ใช้เลือกภายหลัง ถ้าถาม “ยอดขายของวันจันทร์ในไทย” ต้อง key เป็น LocalDate หลังแปลง Asia/Bangkok วิธีนี้ช่วยไม่ให้รายการหลังเที่ยงคืนไทยหล่นไปอยู่วันก่อนในรายงาน

การ truncate ไม่ใช่การปัดใกล้สุด; ค่า 59.999 วินาทีก็ยังลงนาทีก่อน และการเปลี่ยนเป็นหน่วยวันใน Instant ยึด UTC ไม่ได้รู้ปฏิทินของเขตเวลาใด ถ้ามี daylight saving ใน zone เป้าหมาย ยิ่งต้องใช้ชนิดเวลาแบบ zone-aware สำหรับวันท้องถิ่นครับ

Recap

  • เก็บ event จริงเป็น Instant แล้ว truncate สำหรับ bucket สั้น
  • ใช้ ZoneId ก่อนหา LocalDate ของผู้ใช้
  • ทดสอบค่าชิดขอบนาทีและขอบวัน
  • ระบุว่า bucket ที่รายงานเป็น UTC หรือท้องถิ่น