Dart: การใช้งาน Duration เพื่อคำนวณระยะเวลา

Duration class ใช้สำหรับเก็บค่าช่วงเวลาที่ต้องการ โดยหน่วยที่ใหญ่ที่สุดคือ วัน เล็กที่สุดคือ ไมโครวินาที เป็น Class ที่ใช้สำหรับเก็บข้อมูลผลการคำนวณของ DateTime class รวมถึงการใช้ระบุช่วงเวลา เช่น Stopwatch class และอีกหลาย class ที่ต้องอ้างอิงเกี่ยวกับระยะเวลาอีกด้วย

การสร้าง Duration

ตัว Duration จะมี Duration() constructor เพื่อใช้ในการสร้างช่วงเวลาที่ต้องการ ค่าเริ่มต้นคือ 0 หากผู้ใช้งานกำหนดค่า วัน เวลา และอื่น ๆ จะนำค่าทั้งหมดมารวมกัน

ตัว constructor จะรับค่าที่เป็นตัวแปรดังนี้

const Duration({
  int days = 0,
  int hours = 0,
  int minutes = 0,
  int seconds = 0,
  int milliseconds = 0,
  int microseconds = 0,
})

ตัวอย่างการสร้าง Duration ที่มีค่าเวลา 1 วัน และ 1 วันครึ่ง (1 วันกับอีก 12 ชั่วโมง)

var oneDay = Duration(days: 1);
var oneAndHalfDay = Duration(days: 1, hours: 12);

print(oneDay); // output → 24:00:00.000000
print(oneAndHalfDay); // output → 36:00:00.000000

ในการกำหนดค่าตัวแปรของเวลาเหล่านี้ สามารถกำหนดค่าตัวเลขได้ตามความต้องการ ตัว class จะนำไปคำนวณปัดให้เป็นหน่วยที่ถูกต้องให้อัตโนมัติ เช่น หากกำหนดค่า hours เป็น 36 ชั่วโมง

var oneAndHalfDay = Duration(hours: 36);
print(oneAndHalfDay); // output → 36:00:00.000000
print(oneAndHalfDay.inDays); // output → 1
print(oneAndHalfDay.inHours); // output → 36
print(oneAndHalfDay.inMinutes); // output → 2160
print(oneAndHalfDay.inSeconds); // output → 129600

ในการใช้งานจริง สามารถนำตัว Duration ไปคำนวณ เช่น เอาไปลบกัน ดังนั้นตัว Duration สามารถเก็บค่าติดลบได้

var overDayAgo = Duration(days: -1, hours: -10);
print(overDayAgo.inDays); // -1
print(overDayAgo.inHours); // -34
print(overDayAgo.inMinutes); // -2040

var halfDay = Duration(days: 1, hours: -12);
print(halfDay.inDays); // output → 0
print(halfDay.inHours); // output → 12
print(halfDay.inMinutes); // output → 720

การเข้าถึงค่าเวลา

ผู้ใช้งานสามารถแสดงค่าเวลาที่เก็บใน Duration ในหน่วยต่าง ๆ ได้ดังนี้

  • .inDays แสดงในหน่วย วัน
  • .inHours แสดงในหน่วย ชั่วโมง
  • .inMinutes แสดงในหน่วย นาที
  • .inSeconds แสดงในหน่วย วินาที
  • .inMilliseconds แสดงในหน่วย มิลลิวินาที
  • .inMicroseconds แสดงในหน่วย ไมโครวินาที
Dsmurat, penubag, Jelican9, CC BY-SA 4.0

ในการคำนวณค่าเวลาในแต่ละหน่วย หากมีเศษ จะใช้วิธีการปัดลง⬇️ (round down)

var d1 = Duration(days: 1, hours: 23);
print(d1.inDays); // output → 1 

var h1 = Duration(hours: 1, minutes: 59, seconds: 59);
print(h1.inHours); // output → 1
print(h1.inMinutes); // output → 119

บวก ลบ คูณ หาร ค่า Duration

การบวก +

+ นำค่า Duration จำนวน 2 ตัวมารวมกัน แล้วคืนเป็น Duration ตัวใหม่ที่เป็นผลรวม

var t1 = Duration(hours: 1);
var t2 = Duration(days: 1, minutes: 1);
var result = t1 + t2;
print(result); // output → 25:01:00.000000

var time1 = Duration(days: 1) + Duration(days: 9) + Duration(hours: 12);
print(time1); // output → 252:00:00.000000
print(time1.inDays); // output → 10
print(time1.inHours); // output → 252

การลบ -

- นำค่า Duration จำนวน 2 ตัวมาลบกัน แล้วคืนเป็น Duration ตัวใหม่ที่เป็นผลที่ลบได้

var t1 = Duration(days: 1, hours: 1);
var t2 = Duration(hours: 1);
var result = t1 - t2;
print(result); // output → 24:00:00.000000

var time1 = Duration(days: 1) - Duration(days: 11) - Duration(hours: 12);
print(time1); // output → -252:00:00.000000
print(time1.inDays); // output → -10
print(time1.inHours); // output → -252

การคูณ *

* นำค่าตัวเลขมาคูณกับ Duration แล้วคืนเป็น Duration ตัวใหม่ที่เป็นผลที่คูณ หากผลการคูณมีเศษในหน่วยไมโครวินาที จะใช้วิธีการ .round() เพื่อให้เป็นจำนวนเต็ม

var result = t1 * 3;
print(result); // output → 30:00:00.000000

var h1 = Duration(hours: 1);
var h149 = h1 * 1.49;
var h150 = h1 * 1.50;
print(h1); // output → 1:00:00.000000
print(h149); // output → 1:29:24.000000
print(h150); // output → 1:30:00.000000

var micro10 = Duration(microseconds: 10);
var micro49 = micro10 * 1.049; // round(10.49) → 10
var micro50 = micro10 * 1.050; // round(10.5) → 11
print(micro10); // output → 0:00:00.000010
print(micro49); // output → 0:00:00.000010
print(micro50); // output → 0:00:00.000011

การหาร ~/

~/ หารแบบปัดเศษทิ้ง ที่เป็นแบบนี้เนื่องจากตัว Duration class ไม่สามารถเก็บข้อมูลที่เล็กกว่าไมโครวินาทีได้ ดังนั้นหากผลลัพธ์จากการหารมีค่าน้อยกว่า 1 ไมโครวินาที จะไม่สามารถเก็บค่าดังกล่าวได้ และปัดเศษทิ้งไป

หากใช้การหารวัน เวลาในระดับชั่วโมง นาที วินาที ที่ไม่ได้ลงในระดับน้อยกว่าวินาที ไม่จำเป็นต้องกังวลอะไร เนื่องไม่มีผลในการใช้งานจริง

var h3 = Duration(hours: 3);
print(h3 ~/ 2); // output → 1:30:00.000000

var d1 = Duration(days: 1);
print(d1 ~/ 2); //output → 12:00:00.000000
print(d1 ~/ 3); //output → 8:00:00.000000
print(d1 ~/ 10); //output → 2:24:00.000000

var s1 = Duration(seconds: 1);
print(s1 ~/ 60); //output → 0:00:00.016666
print(s1 ~/ 1000); //output → 0:00:00.001000
print(s1 ~/ 1000000); //output → 0:00:00.000001
print(s1 ~/ 1000001); //output → 0:00:00.000000

จากตัวอย่าง ลองสังเกตุผลที่ได้จากการหาร

  • หาร 3 ชั่วโมงด้วย 2 จะได้ค่าเป็น 1 ชั่วโมง 30 นาที หรือ 1.5 ชั่วโมง
  • หาร 1 วันด้วย 2 จะได้ 12 ชั่วโมง, หาร 3 จะได้ 8 ชั่วโมง, หาร 10 จะได้ 2 ชั่วโมง 24 นาที หรือ 144 นาที เอา 144 * 10 = 1440 นาที = 24 * 60 นาที
  • หาร 1 วินาทีด้วย 60 จะได้ 16.666 มิลลิวินาที หรือ 16666 ไมโครวินาที จะเห็นว่าผลที่ได้ปัดเศษทิ้งไป เพราะ 16666 * 60 = 999960 ไมโครวินาที หายไป 40 ไมโครวินาที

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

เนื่องจาก Duration จัดว่าเป็นข้อมูลประเภท int ชนิดหนึ่ง ดังนั้นมันจึงรองรับการเปรียบเทียบด้วย < <= == > >= เหมือนตัวเลขทั่วไป

การสลับค่า + -

หากต้องการค่าที่ไม่ติดลบของ Duration ให้ใช้คำสั่ง .abs()

var t1 = Duration(hours: 1);
var t10 = Duration(hours: 10);
var result = t1 - t10;
print(result); // output → -9:00:00.000000

var positiveResult = result.abs();
print(positiveResult); // output → 9:00:00.000000

ในกรณีที่ต้องการค่าเป็นลบของ Duration ให้ใช้ -

var t1 = Duration(hours: 1);
var t2 = -t1;
print(t2); // output → -1:00:00.000000 

ทดสอบว่าค่า Duration ติดลบหรือไม่ด้วยคำสั่ง .isNegative

var t1 = Duration(hours: -1);
print(t1); // output → -1:00:00.000000
print(t1.isNegative); // output → true

ค่าคงที่ที่น่าสนใจ ช่วยให้ทำงานได้ง่ายขึ้น

ในการตั้งเวลาในการเขียนแอปส่วนใหญ่ มักจะกำหนดในหน่วย มิลลิวินาที หากต้องการเปรียบเทียบในหน่วยที่ใหญ่ขึ้น เช่น นาที ชั่วโมง จำเป็นต้องมาใส่ตัวเลขเข้าไปเองเช่น 1 ชั่วโมง = 60 * 60 * 1000 = 3600000 มิลลิวินาที ใน Duration class มีค่าคงที่เหล่านี้ให้ใช้งาน Duration.microsecondsPerHour จะได้ไม่ต้องมาเขียนตัวเลขคูณ หรือตั้งค่า constant เพิ่ม

  • .hoursPerDay → จำนวน ชั่วโมง ต่อ วัน
  • .minutesPerDay → จำนวน นาที ต่อ วัน
  • .minutesPerHour → จำนวน นาที ต่อ ชั่วโมง
  • .secondsPerDay → จำนวน วินาที ต่อ วัน
  • .secondsPerHour → จำนวน วินาที ต่อ ชั่วโมง
  • .secondsPerMinute → จำนวน วินาที ต่อ นาที
  • .millisecondsPerDay → จำนวน มิลลิวินาที ต่อ วัน
  • .millisecondsPerHour → จำนวน มิลลิวินาที ต่อ ชั่วโมง
  • .millisecondsPerMinute → จำนวน มิลลิวินาที ต่อ นาที
  • .millisecondsPerSecond → จำนวน มิลลิวินาที ต่อ วินาที
  • .microsecondsPerDay → จำนวน ไมโครวินาที ต่อ วัน
  • .microsecondsPerHour → จำนวน ไมโครวินาที ต่อ ชั่วโมง
  • .microsecondsPerMinute → จำนวน ไมโครวินาที ต่อ นาที
  • .microsecondsPerSecond → จำนวน ไมโครวินาที ต่อ วินาที
  • .microsecondsPerMillisecond → จำนวน ไมโครวินาที ต่อ มิลลิวินาที

Duration สามารถเก็บค่าระยะเวลาได้สูงสุดกี่วัน

Duration class จะใช้วิธีเก็บค่าตัวเลข int ในหน่วย ไมโครวินาที ค่าที่เก็บได้คือ -9,223,372,036,854,775,808 ถึง 9,223,372,036,854,775,807 ไมโครวินาที

หากคำนวณกลับเป็นวันจะได้ค่าเป็น 106,751,991 วัน หรือประมาณ 292,271 ปี

ดังนั้นในการใช้งานทั่วไปโอกาสที่จะเกิด overflow จึงน่าจะเป็นเรื่องยากพอสมควร😆

var minValue = Duration(microseconds: -9223372036854775808);
var maxValue = Duration(microseconds: 9223372036854775807);
// Days
print(minValue.inDays); // output → -106751991
print(maxValue.inDays); // output → 106751991
// Years
print((minValue.inDays / 365.25).round()); // output → -292271
print((maxValue.inDays / 365.25).round()); // output → 292271