Dart: การใช้งาน DateTime class เบื้องต้น

บันทึกวิธีการใช้งาน DateTime class ที่ใช้งานกันบ่อย ๆ

Dsmurat, penubag, Jelican9, CC BY-SA 4.0

ตัว DateTime เมื่อสร้างขึ้นมาแล้ว จะไม่สามารถเปลี่ยนแปลงค่าภายใน object ที่สร้างขึ้นมาได้อีก

การสร้าง DateTime

DateTime มีตัว constructor ที่มีให้ใช้งานจะมีดังนี้

  1. DateTime() เวลาที่สร้างขึ้นจะอ้างอิงจาก local time zone
  2. DateTime.now() เวลา ณ ปัจจุบันอ้างอิงจาก local time zone
  3. DateTime.utc() เวลาที่สร้างขึ้นจะอ้างอิงจาก UTC time zone
  4. DateTime.fromMicrosecondsSinceEpoch() จะใช้ค่าไมโครวินาที (1 ใน ล้านวินาที) ที่นับตั้งแต่ปี ค.ศ.1970
  5. DateTime.fromMillisecondsSinceEpoch() จะใช้ค่ามิลลิวินาที (1 ใน พันวินาที) ที่นับตั้งแต่ปี ค.ศ.1970

local time zone = คือเวลาพื้นที่ของเครื่องที่ใช้งาน เช่น ถ้าประเทศไทย จะเป็น UTC+07:00 ส่วน UTC time zone หรือ เวลาสากลเชิงพิกัด (Coordinated Universal Time) ที่จุดอ้างอิงของเวลาสากลเชิงพิกัดคือที่ลองจิจูด ที่ 0° ซึ่งจะคือตำแหน่งเมืองลอนดอน ประเทศอังกฤษ

void main() {
  var local = DateTime.now();
  var utc = local.toUtc();
  print(local);// output → 2024-08-24 16:43:33.011088
  print(utc);// output → 2024-08-24 09:43:33.011088Z
}

จากตัวอย่าง เครื่องที่ใช้อยู่ประเทศไทย UTC+07:00 เมื่อทำการขอค่าเวลาเป็น UTC จึงได้เวลาที่น้อยกว่า 7 ชั่วโมง (16:43 กับ 09:43)

แผนที่ Time zone จาก Wikipedia

การสร้างเวลาโดยใช้ตัวเลข วัน เดือน ปี ชั่วโมง นาที วินาที

DateTime() constructor จะต้องระบุตัวเลขของเวลาที่ต้องการสร้าง โดยอย่างน้อยสุดต้องระบุปี ซึ่งผลที่ได้จะเป็นวันและเวลาเริ่มต้นของปีดังกล่าว

DateTime(
  int year, [
  int month = 1,
  int day = 1,
  int hour = 0,
  int minute = 0,
  int second = 0,
  int millisecond = 0,
  int microsecond = 0,
])

ส่วน DateTime.utc() constructor จะมี parameters เหมือนกัน แต่ตัวเวลาที่ระบุจะเป็นเวลาที่ UTC+0

void main() {
  // first date and time in year 2024
  var year2024 = DateTime(2024); // local time is UTC+7
  var year2024utc = DateTime.utc(2024);
  print(year2024); // output → 2024-01-01 00:00:00.000
  print(year2024.toUtc()); // output → 2023-12-31 17:00:00.000Z 
  print(year2024utc); // output → 2024-01-01 00:00:00.000Z

  // last day on year 2024
  var endOf2024 = DateTime(2024, 12, 31);
  print(endOf2024); // output → 2024-12-31 00:00:00.000

  // before new year
  var before2025 = DateTime(2024, 12, 31, 23, 59, 59, 999);
  print(before2025); // output → 2024-12-31 23:59:59.999
}

การสร้างจากเวลาวินาที ที่นับจากปี 1970 (Unix Epoch)

ในระบบคอมพิวเตอร์จะใช้ Unix Epoch เป็นช่วงเวลาในการอ้างอิงจุดเริ่มนับเวลาเป็น 0 คือ วันที่ 1 มกราคา ปี ค.ศ.1970 เวลา 00:00น. โดยในเซิร์ฟเวอร์มันจะใช้ค่าผลต่างเวลาดังกล่าวในการอ้างอิงถึงเวลาปัจจุบัน หรืออ้างอิงเวลา ณ จุดที่ต้องการ โดยหน่วยที่ Dart รองรับคือ มิลลิวินาที (ms.) และ ไมโครวินาที (µs.)

// first UTC date and time in year 2024 AD
var year1970utc = DateTime.utc(1970);
print(year1970utc); // output → 1970-01-01 00:00:00.000Z
print(year1970utc.millisecondsSinceEpoch); // output → 0
print(year1970utc.microsecondsSinceEpoch); // output → 0

// 1 day has 24*60*60*1000 = 86400000 ms.
var day1utc = DateTime.fromMillisecondsSinceEpoch(86400000, isUtc: true);
print(day1utc); // output → 1970-01-02 00:00:00.000Z

// year 9999 AD
var year2999utc = DateTime.utc(9999);
print(year2999utc); // output → 9999-01-01 00:00:00.000Z
print(year2999utc.millisecondsSinceEpoch); // output → 253370764800000
print(year2999utc.microsecondsSinceEpoch); // output → 253370764800000000

ปกติในการใช้งานทั่วไป การแสดงและคำนวณเวลาในแอป ไม่ค่อยได้ใช้หน่วย ms. และ µs. ในการสร้างเวลาเพื่อใช้งาน แต่มันจะเป็นการเอาค่าที่คืนมาจากเซิร์ฟเวอร์ ที่มักรองรับการคืนค่ากลับมาเป็น ms.

สำหรับข้อมูลเวลาหากใช้งานด้วยคอมพิวเตอร์ 64-bit จะสามารถอ้างเวลาได้เกินปี ค.ศ. 9999 ไปอีกเป็นพันล้านปีเลย ซึ่งตัวคนเขียนคงไม่มีโอกาศในใช้งานขนาดนั้น 😂

การสร้างเวลาจาก String

นอกจาก constructor ที่มีให้แล้ว ตัว DateTime ยังมี static method ที่ช่วยแปลง String เป็นข้อมูล DateTime ได้ ข้อความที่เป็นวันที่ ตัว DateTime รองรับรูปแบบย่อยต่าง ๆ ใน ISO 8601 โดยใช้ผ่านคำสั่ง DateTime.parse() และ DateTime.tryParse() โดยความแตกต่างของ 2 คำสั่งนี้คือ DateTime.parse() ถ้าทำไม่สำเร็จจะ throw FormatException กลับมา แต่ DateTime.tryParse() ถ้าทำไม่สำเร็จจะคืนค่ากลับมาเป็น null

ตัวอย่างรูปแบบข้อความที่สามารถแปลงเป็น DateTime ได้

  • "2012-02-27"
  • "2012-02-27 13:27:00"
  • "2012-02-27 13:27:00.123456789z"
  • "2012-02-27 13:27:00,123456789z"
  • "20120227 13:27:00"
  • "20120227T132700"
  • "20120227"
  • "+20120227"
  • "2012-02-27T14Z"
  • "2012-02-27T14+00:00"
  • "-123450101 00:00:00 Z": in the year -12345.
  • "2002-02-27T14:00:00-0500": Same as "2002-02-27T19:00:00Z"
// local time
var onlyDate = DateTime.parse("20240101");
print(onlyDate); // output → 2024-01-01 00:00:00.000

var dateAndTime = DateTime.parse("20240101 120000");
print(dateAndTime); // output → 2024-01-01 12:00:00.000

var dateAndTime2 = DateTime.parse("2024-01-01 12:00:00");
print(dateAndTime2); // output → 2024-01-01 12:00:00.000
print(dateAndTime2.isUtc); // output → false

// utc+0 time
var testUtc = DateTime.parse("2024-01-01 12:00:00Z"); // same as 2024-01-01 12:00:00+00:00
print(testUtc); // output → 2024-01-01 12:00:00.000Z
print(testUtc.isUtc); // output → true

// utc+7 time
var bkkTime = DateTime.parse("2024-01-01 12:00:00+07:00");
print(bkkTime); // output → 2024-01-01 05:00:00.000Z
print(bkkTime.isUtc); // output → true
print(bkkTime.toUtc()); // output → 2024-01-01 05:00:00.000Z
print(bkkTime.toLocal()); // output → 2024-01-01 12:00:00.000

การตรวจสอบ time zone

หากต้องการทราบว่าแอปที่ทำงานอยู่ ใช้ time zone อะไร สามารถใช้คำสั่ง .timeZoneName และ .timeZoneOffset ได้ โดย .timeZoneOffset จะคืนค่ากลับมาเป็น Duration class

var localTime = DateTime(2000, 1, 5);
print(localTime.timeZoneName); // output → SE Asia Standard Time
print(localTime.timeZoneOffset); // output → 7:00:00.000000

var utcTime = localTime.toUtc();
print(utcTime.timeZoneName); // output → UTC
print(utcTime.timeZoneOffset); // output → 0:00:00.000000

การเข้าถึงข้อมูลสมาชิกใน DateTime

ข้อมูลวันที่

  • .day วันที่ 1 - 31
  • .month เดือน 1 - 12
  • .year ปี ค.ศ.
  • .weekday วันในสัปดาห์ monday - sunday (เป็นค่า int คือ 1 - 7)

ข้อมูลเวลา

var localTime = DateTime(2000, 1, 5, 10, 30, 0, 500, 100);
print(localTime); //output → 2000-01-05 10:30:00.500100
print(localTime.day); //output → 5
print(localTime.month); //output → 1
print(localTime.year); //output → 2000
print(localTime.weekday); //output → 3
print(localTime.hour); //output → 10
print(localTime.minute); //output → 30
print(localTime.second); //output → 0
print(localTime.millisecond); //output → 500
print(localTime.microsecond); //output → 100

การ บวก ลบ วันที่

การบวก

การบวก เพิ่มค่าเข้าไปใน DateTime สามารถทำได้โดยใช้คำสั่ง .add() โดยส่งผ่านค่า Duration class ที่ต้องการเพิ่มเข้าไป

var year2000 = DateTime(2000);
print(year2000); // output → 2000-01-01 00:00:00.000
print(year2000.add(Duration(days: 10))); // output → 2000-01-11 00:00:00.000
print(year2000.add(Duration(hours: 12))); // output → 2000-01-01 12:00:00.000
print(year2000.add(Duration(days: 1, hours: 12, minutes: 30))); // output → 2000-01-02 12:30:00.000

การลบ

การลบ เพิ่มค่าเข้าไปใน DateTime สามารถทำได้โดยใช้คำสั่ง .subtract() โดยส่งผ่านค่า Duration class ที่ต้องการเพิ่มเข้าไป

var year2000 = DateTime(2000);
print(year2000); // output → 2000-01-01 00:00:00.000
print(year2000.subtract(Duration(days: 10))); // output → 1999-12-22 00:00:00.000
print(year2000.subtract(Duration(hours: 12))); // output → 1999-12-31 12:00:00.000
print(year2000.subtract(Duration(days: 1, hours: 12, minutes: 30))); // output → 1999-12-30 11:30:00.000

การหาผลต่างของเวลา 2 เวลา

ผลต่างของ 2 เวลา สามารถใช้คำสั่ง .difference() ผลที่ได้จะออกมาเป็น Duration class

var date15 = DateTime(2000, 1, 15);
var date10 = DateTime(2000, 1, 10);

var diff_15_10 = date15.difference(date10);
print(diff_15_10.inDays); // output → 5
print(diff_15_10.inHours); // output → 120
print(diff_15_10); // output → 120:00:00.000000

var diff_10_15 = date10.difference(date15);
print(diff_10_15.inDays); // output → -5
print(diff_10_15.inHours); // output → -120
print(diff_10_15); // output → -120:00:00.000000

var time15 = DateTime(2000, 1, 1, 15, 0);
var time10 = DateTime(2000, 1, 1, 10, 0);

var diff2 = time15.difference(time10);
print(diff2.inDays); // output → 0
print(diff2.inHours); // output → 5
print(diff2); // output → 5:00:00.000000

การเปรียบเทียบเวลาว่าอยู่ก่อน หรือ หลัง

การเปรียบเทียบเวลาว่ามากกว่าเวลา หรืออยู่หลังที่กำหนดหรือไม่ ให้ใช้คำสั่ง .isAfter() ในการตรวจสอบ

var date10 = DateTime(2000, 1, 10);
var date15 = date10.add(Duration(days: 5));
print(date10.isAfter(date15)); // output → false
print(date15.isAfter(date10)); // output → true

การเปรียบเทียบเวลาว่าอยู่ก่อน หรือน้อยกว่าเวลาที่กำหนดหรือไม่ ให้ใช้คำสั่ง .isBefore() ในการตรวจสอบ

var date10 = DateTime(2000, 1, 10);
var date15 = date10.add(Duration(days: 5));
print(date10.isBefore(date15)); // output → true
print(date15.isBefore(date10)); // output → false

หรือหากใครที่ถนัดคำสั่ง .compareTo() ก็ใช้คำสั่งนี้เปรียบเทียบได้เหมือนกัน โดยจะให้ผลออกมาเป็น

  • a < b → ค่าลบ
  • a == b → 0
  • a > b → ค่าบวก
final now = DateTime.now();
final future = now.add(const Duration(days: 2));
final past = now.subtract(const Duration(days: 2));
final newDate = now.toUtc();

print(now.compareTo(future)); // -1
print(now.compareTo(past)); // 1
print(now.compareTo(newDate)); // 0

การเปรียบเทียบว่า เวลาทั้งสอง เป็นเวลาเดียวกันหรือไม่

เพื่อไม่ให้สับสน การเปรียบเทียบเวลาในที่นี่คือ วันและเวลามีค่าเดียวกัน โดยจะใช้หลักว่าเมื่อเวลาทั้งสองอยู่ใน time zone เดียวกัน จะเท่ากันหรือไม่ ใช้คำสั่ง .isAtSameMomentAs()

var localTime = DateTime.parse("2000-01-01 12:00:00");
var utcTime = localTime.toUtc();
print(localTime.isAtSameMomentAs(utcTime)); // output → true

print(localTime.difference(utcTime)); // output → 0:00:00.000000
print(localTime.compareTo(utcTime)); // output → 0
print(localTime.isUtc); // output → false
print(utcTime.isUtc); // output → true

// don't use == to compare time value
print(localTime == utcTime); // output → false
var utcTime2 = utcTime.toUtc(); // returns this DateTime if it is already in UTC
print(utcTime == utcTime2); // output → true

การแปลงค่าเวลา ออกมาเป็นข้อความตามรูปแบบที่กำหนด

เมื่อต้องการแปลงเวลาออกมาเป็นข้อความ สามารถใช้คำสั่ง .toString() กับ .toIso8601String() โดยรูปแบบจะเป็นแบบตายตัว

var localTime = DateTime.now();
print(localTime.toString()); // → 2024-08-24 22:10:43.770278
print(localTime.toIso8601String()); // → 2024-08-24T22:10:43.770278

หากต้องการจัดรูปแบบวันที่และเวลา ในแบบที่ต้องการ วิธีที่ง่ายและสะดวกโดยไม่ต้องมาเขียนเพิ่มเองคือใช้ DateFormat class ใน intl package

import 'package:intl/intl.dart';

void main() {
  final DateTime now = DateTime(2000, 1, 5);
  final DateFormat formatter = DateFormat('d/M/yyyy');
  final String formatted = formatter.format(now);
  print(formatted); // output → 5/1/2000
}

หรือถ้าจะเขียนเองโดยไม่ใช่ intl package ก็สามารถทำได้ เนื่องจากตัว DateTime มีคำสั่งในการเข้าถึงข้อมูลวันที่และเวลาอยู่แล้ว ก็นำมาแปลงให้อยู่ในรูปแบบที่ต้องการได้ผ่านคำสั่งใน String class เป็นต้น

var today = DateTime(2000, 1, 5);
print('${today.day}/${today.month}/${today.year}'); // output → 5/1/2000

// date and month with 2 digit
var dd = today.day.toString().padLeft(2, '0');
var mm = today.month.toString().padLeft(2, '0');
print('$dd/$mm/${today.year}'); // output → 05/01/2000