ไทย

คู่มือฉบับสมบูรณ์สำหรับการใช้ Temporal API ของ JavaScript เพื่อการคำนวณช่วงเวลาที่แม่นยำและเข้าใจง่าย ครอบคลุมตั้งแต่การสร้าง duration พื้นฐานไปจนถึงการคำนวณและการจัดรูปแบบขั้นสูง

JavaScript Temporal Duration: การคำนวณช่วงเวลาอย่างเชี่ยวชาญ

Temporal API ของ JavaScript นำเสนอวิธีที่ทันสมัยและทรงพลังในการจัดการกับวันที่ เวลา และช่วงเวลา อ็อบเจกต์ Temporal.Duration แทนความยาวของเวลา ซึ่งเป็นแนวทางที่ชัดเจนและเข้าใจง่ายในการคำนวณกับช่วงเวลา บทความนี้จะเจาะลึกรายละเอียดของ Temporal.Duration โดยสาธิตวิธีการสร้าง จัดการ และจัดรูปแบบระยะเวลาสำหรับการใช้งานในกรณีต่างๆ

Temporal.Duration คืออะไร?

Temporal.Duration แทนช่วงของเวลา โดยแสดงในรูปของปี เดือน วัน ชั่วโมง นาที วินาที และเศษส่วนของวินาที (มิลลิวินาที ไมโครวินาที นาโนวินาที) ซึ่งแตกต่างจากอ็อบเจกต์ Date ที่แทนจุดเวลาที่เฉพาะเจาะจง Temporal.Duration จะแทนจำนวนของเวลา โดยยึดตามรูปแบบระยะเวลาของ ISO 8601 (เช่น P1Y2M10DT2H30M แทน 1 ปี 2 เดือน 10 วัน 2 ชั่วโมง และ 30 นาที) Temporal API ถูกออกแบบมาให้ใช้งานง่ายและมีโอกาสเกิดข้อผิดพลาดน้อยกว่าอ็อบเจกต์ Date แบบดั้งเดิม

การสร้างอ็อบเจกต์ Temporal.Duration

มีหลายวิธีในการสร้างอ็อบเจกต์ Temporal.Duration:

1. จาก Plain Object

คุณสามารถสร้าง duration ได้โดยการส่งผ่านอ็อบเจกต์ที่มีคุณสมบัติตามที่ต้องการ:

const duration = new Temporal.Duration(1, 2, 10, 2, 30, 0, 0, 0);
console.log(duration.toString()); // ผลลัพธ์: P1Y2M10DT2H30M

โค้ดนี้จะสร้าง duration ที่มีระยะเวลา 1 ปี 2 เดือน 10 วัน 2 ชั่วโมง และ 30 นาที โปรดทราบว่าอาร์กิวเมนต์จะเรียงตามลำดับต่อไปนี้: years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds.

2. จากสตริง ISO 8601

คุณยังสามารถสร้าง duration จากสตริงระยะเวลาตามมาตรฐาน ISO 8601 โดยใช้ Temporal.Duration.from():

const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.toString()); // ผลลัพธ์: P1Y2M10DT2H30M

วิธีนี้มีประโยชน์อย่างยิ่งเมื่อต้องจัดการกับ duration ที่เก็บอยู่ในรูปแบบสตริงหรือได้รับมาจากแหล่งข้อมูลภายนอก

3. การใช้เมธอด add() และ subtract() กับ Temporal.Instant, Temporal.ZonedDateTime เป็นต้น

เมื่อคุณบวกหรือลบ Temporal.Duration จากประเภท Temporal อื่นๆ (เช่น Temporal.Instant หรือ Temporal.ZonedDateTime) และจากนั้นนำค่าทั้งสองมาลบกัน จะได้ผลลัพธ์เป็น Temporal.Duration ที่แสดงถึงความแตกต่างระหว่างจุดเวลาทั้งสอง ตัวอย่างเช่น:

const now = Temporal.Now.zonedDateTimeISO();
const later = now.add({ hours: 5 });
const duration = later.since(now);
console.log(duration.toString()); // ผลลัพธ์: PT5H

การเข้าถึงส่วนประกอบของ Duration

คุณสามารถเข้าถึงส่วนประกอบแต่ละส่วนของอ็อบเจกต์ Temporal.Duration ได้โดยใช้คุณสมบัติต่างๆ ของมัน:

const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.years);      // ผลลัพธ์: 1
console.log(duration.months);     // ผลลัพธ์: 2
console.log(duration.days);       // ผลลัพธ์: 10
console.log(duration.hours);      // ผลลัพธ์: 2
console.log(duration.minutes);     // ผลลัพธ์: 30
console.log(duration.seconds);     // ผลลัพธ์: 0
console.log(duration.milliseconds); // ผลลัพธ์: 0
console.log(duration.microseconds); // ผลลัพธ์: 0
console.log(duration.nanoseconds);  // ผลลัพธ์: 0

การคำนวณทางคณิตศาสตร์กับ Durations

อ็อบเจกต์ Temporal.Duration รองรับการบวกและการลบโดยใช้เมธอด add() และ subtract() เมธอดเหล่านี้จะคืนค่าอ็อบเจกต์ Temporal.Duration ใหม่ซึ่งเป็นผลลัพธ์ของการดำเนินการ

const duration1 = Temporal.Duration.from("P1Y2M");
const duration2 = Temporal.Duration.from("P3M4D");

const addedDuration = duration1.add(duration2);
console.log(addedDuration.toString()); // ผลลัพธ์: P1Y5M4D

const subtractedDuration = duration1.subtract(duration2);
console.log(subtractedDuration.toString()); // ผลลัพธ์: P10M26D

คุณยังสามารถเชื่อมต่อเมธอดเหล่านี้เพื่อการคำนวณที่ซับซ้อนยิ่งขึ้นได้:

const duration = Temporal.Duration.from("P1D").add({ hours: 12 }).subtract({ minutes: 30 });
console.log(duration.toString()); // ผลลัพธ์: P1DT11H30M

เมธอด negated() จะคืนค่าอ็อบเจกต์ Temporal.Duration ใหม่โดยที่ส่วนประกอบทั้งหมดมีค่าเป็นลบ:

const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const negatedDuration = duration.negated();
console.log(negatedDuration.toString()); // ผลลัพธ์: -P1Y2M10DT2H30M

เมธอด abs() จะคืนค่าอ็อบเจกต์ Temporal.Duration ใหม่โดยที่ส่วนประกอบทั้งหมดมีค่าเป็นบวก (ค่าสัมบูรณ์):

const duration = Temporal.Duration.from("-P1Y2M10DT2H30M");
const absoluteDuration = duration.abs();
console.log(absoluteDuration.toString()); // ผลลัพธ์: P1Y2M10DT2H30M

เมธอด with() ช่วยให้คุณสร้างอินสแตนซ์ Temporal.Duration ใหม่โดยเปลี่ยนคุณสมบัติบางส่วนหรือทั้งหมดเป็นค่าใหม่ หากไม่ได้ระบุค่าใดในอ็อบเจกต์อาร์กิวเมนต์ ค่าดั้งเดิมของ duration จะถูกนำมาใช้แทน ตัวอย่างเช่น:

const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const newDuration = duration.with({ years: 2, days: 5 });
console.log(newDuration.toString()); // ผลลัพธ์: P2Y2M5DT2H30M

การปรับมาตรฐาน (Normalizing) Durations

บางครั้ง Durations อาจแสดงในรูปแบบที่ยังไม่ได้ปรับมาตรฐาน (เช่น P1Y12M ซึ่งสามารถทำให้ง่ายขึ้นเป็น P2Y) เมธอด normalized() จะพยายามลดรูป duration ให้อยู่ในรูปแบบที่กระชับที่สุด อย่างไรก็ตาม เมธอดนี้ต้องการวันที่อ้างอิงเพื่อจัดการกับความซับซ้อนของจำนวนวันที่แตกต่างกันในแต่ละเดือน ในการปรับมาตรฐานอย่างถูกต้อง คุณจะต้องมีอินสแตนซ์ของ Temporal.PlainDate, Temporal.ZonedDateTime, หรือ Temporal.Instant

ตัวอย่างเช่น การปรับมาตรฐาน duration ที่เกี่ยวข้องกับเดือนและวันจำเป็นต้องมีวันที่อ้างอิง:

const duration = Temporal.Duration.from("P1M32D");
const referenceDate = Temporal.PlainDate.from("2024-01-01");
const normalizedDuration = duration.normalized({ relativeTo: referenceDate });
console.log(normalizedDuration.toString()); // ผลลัพธ์: P2M1D

ในตัวอย่างนี้ duration P1M32D ถูกปรับมาตรฐานโดยอ้างอิงกับวันที่ 1 มกราคม 2024 ทำให้ได้ผลลัพธ์เป็น P2M1D เนื่องจากเดือนมกราคมมี 31 วัน

หากคุณจัดการเฉพาะส่วนประกอบของเวลา (ชั่วโมง, นาที, วินาที, ฯลฯ) คุณสามารถปรับมาตรฐานได้โดยไม่ต้องใช้วันที่อ้างอิง:

const duration = Temporal.Duration.from("PT25H61M");
const normalizedDuration = duration.normalized({ relativeTo: null }); //หรือละเว้นอาร์กิวเมนต์ relativeTo
console.log(normalizedDuration.toString()); // ผลลัพธ์: P1DT2H1M

การเปรียบเทียบ Durations

คุณสามารถเปรียบเทียบ duration โดยใช้เมธอด compare() เมธอดนี้จะคืนค่า:

const duration1 = Temporal.Duration.from("P1Y");
const duration2 = Temporal.Duration.from("P6M");

const comparisonResult = Temporal.Duration.compare(duration1, duration2);
console.log(comparisonResult); // ผลลัพธ์: 1

ตัวอย่างการใช้งานจริง

1. การคำนวณเวลาจนกว่าจะถึงกิจกรรม

สมมติว่าคุณต้องการคำนวณเวลาที่เหลือก่อนจะถึงกิจกรรมที่กำหนด โดยใช้ Temporal.Now.zonedDateTimeISO() เพื่อรับเวลาปัจจุบัน และลบด้วยวันที่ของกิจกรรม หากวันที่ของกิจกรรมผ่านไปแล้ว ผลลัพธ์ที่ได้จะเป็นค่าลบ

const eventDate = Temporal.ZonedDateTime.from({ timeZone: 'America/Los_Angeles', year: 2024, month: 12, day: 25, hour: 9, minute: 0, second: 0 });
const now = Temporal.Now.zonedDateTimeISO('America/Los_Angeles');

const durationUntilEvent = eventDate.since(now);

console.log(durationUntilEvent.toString()); // ผลลัพธ์: เช่น P262DT14H30M (ขึ้นอยู่กับวันและเวลาปัจจุบัน)

2. การติดตามระยะเวลาของงานในโปรเจกต์

ในการบริหารจัดการโครงการ คุณสามารถใช้ Temporal.Duration เพื่อติดตามระยะเวลาที่ประเมินไว้หรือระยะเวลาที่ใช้จริงของงานต่างๆ

const task1EstimatedDuration = Temporal.Duration.from("PT8H"); // 8 ชั่วโมง
const task2EstimatedDuration = Temporal.Duration.from("PT16H"); // 16 ชั่วโมง

const totalEstimatedDuration = task1EstimatedDuration.add(task2EstimatedDuration);
console.log(`ระยะเวลาที่ประเมินทั้งหมด: ${totalEstimatedDuration.toString()}`); // ผลลัพธ์: ระยะเวลาที่ประเมินทั้งหมด: P1DT

3. การคำนวณอายุ

แม้ว่าการคำนวณอายุที่แม่นยำจะต้องคำนึงถึงปีอธิกสุรทินและเขตเวลา แต่ Temporal.Duration ก็สามารถให้ค่าประมาณที่สมเหตุสมผลได้:

const birthDate = Temporal.PlainDate.from("1990-05-15");
const currentDate = Temporal.PlainDate.from("2024-01-20");

const ageDuration = currentDate.since(birthDate, { smallestUnit: 'years' });
console.log(`อายุโดยประมาณ: ${ageDuration.years} ปี`); // ผลลัพธ์: อายุโดยประมาณ: 33 ปี

4. การแสดงผล Duration ในรูปแบบที่มนุษย์อ่านได้

บ่อยครั้งที่คุณจำเป็นต้องแสดงผล duration ในรูปแบบที่มนุษย์สามารถอ่านเข้าใจได้ แม้ว่า Temporal.Duration จะไม่มีฟังก์ชันการจัดรูปแบบในตัว แต่คุณสามารถสร้างตรรกะการจัดรูปแบบเองได้:

function formatDuration(duration) {
  const parts = [];
  if (duration.years) parts.push(`${duration.years} ปี`);
  if (duration.months) parts.push(`${duration.months} เดือน`);
  if (duration.days) parts.push(`${duration.days} วัน`);
  if (duration.hours) parts.push(`${duration.hours} ชั่วโมง`);
  if (duration.minutes) parts.push(`${duration.minutes} นาที`);
  if (duration.seconds) parts.push(`${duration.seconds} วินาที`);

  return parts.join(', ');
}

const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const formattedDuration = formatDuration(duration);
console.log(formattedDuration); // ผลลัพธ์: 1 ปี, 2 เดือน, 10 วัน, 2 ชั่วโมง, 30 นาที

การใช้งานขั้นสูงและข้อควรพิจารณา

1. การจัดการเขตเวลา (Time Zone)

เมื่อต้องจัดการกับช่วงเวลาที่ข้ามขอบเขตของเขตเวลาหรือการเปลี่ยนเวลาตามฤดูกาล (Daylight Saving Time) สิ่งสำคัญคือต้องใช้ Temporal.ZonedDateTime เพื่อให้แน่ใจว่าการคำนวณถูกต้อง การใช้ Temporal.PlainDate และ Temporal.PlainTime จะหลีกเลี่ยงการแปลงเขตเวลาใดๆ

2. หน่วยที่เล็กที่สุดและการปัดเศษ

เมธอด `since()` และ `until()` มักจะยอมรับอ็อพชันเพื่อกำหนดหน่วยที่เล็กที่สุดสำหรับ duration ที่เป็นผลลัพธ์ ตัวอย่างเช่น การคำนวณเวลา *จนกว่า* จะถึงกิจกรรมและจำกัดผลลัพธ์ให้แสดงถึงแค่วัน

const eventDate = Temporal.PlainDate.from("2024-12-25");
const now = Temporal.PlainDate.from("2024-01-20");

const durationUntilEvent = now.until(eventDate, { smallestUnit: 'days' });

console.log(durationUntilEvent.toString()); //ตัวอย่างผลลัพธ์ PT340D

3. อธิกวินาที (Leap Seconds)

Temporal ไม่ได้คำนึงถึงอธิกวินาทีโดยกำเนิด หากคุณต้องการความแม่นยำสูงมาก คุณจะต้องจัดการกับอธิกวินาทีแยกต่างหาก

4. เขตเวลา IANA

Temporal API อาศัยฐานข้อมูลเขตเวลาของ IANA (Internet Assigned Numbers Authority) โปรดตรวจสอบให้แน่ใจว่าสภาพแวดล้อมของคุณมีฐานข้อมูล IANA เวอร์ชันล่าสุดเพื่อจัดการการแปลงเขตเวลาได้อย่างถูกต้อง

แนวทางปฏิบัติที่ดีที่สุด

ข้อผิดพลาดที่พบบ่อย

กรณีการใช้งานจริงในวัฒนธรรมที่แตกต่างกัน

Temporal API มีประโยชน์อย่างยิ่งในแอปพลิเคชันระดับโลกที่ความแตกต่างของเขตเวลาและรายละเอียดทางวัฒนธรรมมีความสำคัญ นี่คือตัวอย่างบางส่วน:

สรุป

Temporal.Duration มอบวิธีที่แข็งแกร่งและใช้งานง่ายในการทำงานกับช่วงเวลาใน JavaScript ด้วยการทำความเข้าใจคุณสมบัติและแนวทางปฏิบัติที่ดีที่สุด คุณจะสามารถทำการคำนวณ duration ที่แม่นยำและเชื่อถือได้ในแอปพลิเคชันของคุณ การนำ Temporal API มาใช้จะนำไปสู่โค้ดที่สะอาดและบำรุงรักษาง่ายขึ้น และลดความเสี่ยงของข้อผิดพลาดที่เกี่ยวข้องกับการจัดการวันที่และเวลาแบบดั้งเดิม

เมื่อคุณเจาะลึกลงไปใน Temporal API อย่าลืมศึกษาเอกสารอย่างเป็นทางการและทดลองกับสถานการณ์ต่างๆ เพื่อให้เข้าใจความสามารถของมันอย่างถ่องแท้ ด้วยการออกแบบที่ทันสมัยและคุณสมบัติที่ครอบคลุม Temporal พร้อมที่จะปฏิวัติวิธีที่เราจัดการกับวันที่ เวลา และ duration ใน JavaScript