การจัดการวันที่และเวลาโดยใช้ DateTime ใน php

เขียนเมื่อ 1 ปีก่อน โดย Ninenik Narkdee
datetimezone dateinterval datetime dateperiod

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ datetimezone dateinterval datetime dateperiod

ดูแล้ว 6,383 ครั้ง


เราได้เคยรู้จักการจัดการวันที่และเวลาใน php ด้วย strtotime() ฟังก์ชั่นไปแล้วในบทความ
ก่อนหน้า เนื้อหานี้ เราจะมาเพิ่มเติมการจัดการวันที่และเวลาด้วยความสามารถของ DateTime
object ที่มีมาให้ใน php 
 
การใช้งานรูปแบบข้อความวันที่และเวลา กับฟังก์ชั่น strtotime() ใน php http://niik.in/800 
 
โดยในเนื้อหานี้จะพยายามนำเอาความสามารถและประโยชน์ต่างๆ ที่จะได้รับเมื่อนำมาปรับใช้งาน
ดูเนื้อหาอ้างอิงได้ที่ https://www.php.net/manual/en/book.datetime.php
 
DateTime class เป็น class ที่เราสามารถใช้ในการจัดการวันที่และเวลา ไม่ว่าจะโดยการส่งค่า
ข้อความ หรือใช้ค่าจากระบบในการสร้างรูปแบบวันที่ขึ้นมาใช้งาน
 
การจัดการวันที่และเวลาบางกรณีเวลาของ server อาจจะไม่ตรง ซึ่งอาจจะเป็นเพราะการกำหนด
timezone ของระบบ ดังนั้นเราอาจจะต้องกำหนด ค่านี้ไว้ในส่วนบนสุดของไฟล์ php หรืออาจจะ
ตั้งค่าให้ server เพียงครั้งเดียวก็ได้
 

การกำหนด timezone ในไฟล์ php
 

<?php
date_default_timezone_set('Asia/Bangkok');
echo date("Y-m-d H:i:s");
 

การกำหนด timezone ด้วยไฟล์ .htaccess
 

กรณีเราต้องการใช้งานทั้งหมดทุกไฟล์ ก็ให้กำหนดค่าด้านล่างนี้ในไฟล์ .htaccess ที่อยู่ root
public_html แต่กรณีต้องการใช้งานในบาง โฟลเดอร์ หรือ path ก็ให้สร้างไว้ในโฟลเดอร์ที่ต้องการ
 
php_value date.timezone 'Asia/Bangkok'
 
 

การสร้าง DateTime object ใหม่ด้วย DateTime และ DateTimeImmutable

 
เมื่อเราเริ่มต้นจะใช้งาน DateTime ใน php จะมี 2 รูปแบบให้เรียกใช้ คือแบบ ที่ค่าของตัวมันสามารถ
เปลี่ยนแปลงได้เมื่อถูกเปลี่ยนแปลง DateTime และแบบที่ค่าของมันไม่สามารถเปลี่ยนแปลงได้ 
DateTimeImmutable ซึ่งทั้งสองรูปแบบมีฟังก์ชั่นหรือ method การใช้งานที่ไม่แตกต่างกันมากนัก
 
ดูตัวอย่างเปรียบเทียบความแตกต่าง
 
// ถ้าวันนี้วันที่ 2022-12-27
$date = new DateTime();
echo $date->format('Y-m-d'); // 2022-12-27
$tomorrow = $date->modify('+1 day'); // เมื่อใช้คำสั่งเปลี่ยนแปลงค่า
echo $date->format('Y-m-d'); // 2022-12-28 ** มีการเปลี่ยนแปลง
echo $tomorrow->format('Y-m-d'); // 2022-12-28
 
สังเกตว่าตัวแปร $date ซึ่งเป็น DateTime object ที่ถูกสร้างด้วย DateTime() ค่าของมันมีการ
เปลี่ยนแปลงไปด้วย ทำให้หลังเปลี่ยนแปลงค่า $date เท่ากับ $tomorrow 
แต่ถ้าเราใช้งาน DateTimeImmutable() จะไม่มีการเปลี่ยนแปลง ดังนี้
 
$date = new DateTimeImmutable();
echo $date->format('Y-m-d'); // 2022-12-27
$tomorrow = $date->modify('+1 day'); // เมื่อใช้คำสั่งเปลี่ยนแปลงค่า
echo $date->format('Y-m-d'); // 2022-12-27 ** ไม่มีการเปลี่ยนแปลง
echo $tomorrow->format('Y-m-d'); // 2022-12-28
 
ดังนั้นการที่เลือกใช้รูปแบบไหน เราต้องตัดสินใจว่า ตัวแปรเริ่มต้นนั้น สามารถเปลี่ยนแปลงได้หรือไม่
แต่ในรูปแบบลักษณะใช้งานในแบบสั้นหรือไม่ต่อเนื้องซับซ้อน รูปแบบธรรมดาก็เพียงพอต่อการใช้งาน
ดังนั้นในที่นี้เราจะใช้รูปแบบ DateTime() ประกอบการอธิบาย
 

การสร้าง DateTime object

การสร้าง DateTime object ค่าเริ่มต้นจะได้เวลา ณ ปัจจุบัน และ timezone ของระบบ
หากต้องการระบุ timezone เข้าไปด้วยสามารถใช้ค่าต่างๆ นี้แทนได้ 
ค่า timezone ต่างๆ ดูได้ที่ https://www.php.net/manual/en/timezones.php
 
$date = new DateTime();
echo $date->format('Y-m-d H:i:s'); // 2022-12-27 12:53:42
$date2 = new DateTime("now", new DateTimeZone("Asia/Shanghai"));
echo $date2->format('Y-m-d H:i:s'); // 22022-12-27 13:53:42
 
ตัวอย่างข้างต้นจะเห็นว่าเวลาที่จีน เร็วกว่าไทย 1 ชั่วโมง
 
เราสามารถใช้งาน ข้อความ String เกี่ยวกับวันที่ต่างๆ ดูเพิ่ม http://niik.in/800
กำหนดในขั้นตอนการสร้าง DateTime object ได้ ตัวอย่างเช่าน
 
// ถ้าวันนี้วันที่ 2022-12-27
$date = new DateTime(); //2022-12-27 13:02:02
$date = new DateTime("now"); //2022-12-27 13:02:02
$date = new DateTime("noon +1 day"); //2022-12-28 12:00:00
$date = new DateTime("2022-12-29 +1 day"); //2022-12-30 00:00:00
 
 

การใช้งานระยะเวลา ช่วงเวลา ระยะห่างของเวลาด้วย DateInterval

ในการใช้งานเกี่ยวกับเวลา บางครั้งเราจำเป็นต้องมีระยะเวลา ช่วงเวลา หรือระยะห่างของเวลา
มาเกี่ยวข้อง เช่น ใช้ในการหาวันล่วงหน้า เวลาล่วงหน้า วันเวลาที่ผ่านมาแล้ว เหล่านี้ DateInterval
ก็จะเป็นค่าที่เราสามารถนำมาใช้งานได้ โดยจะใช้งานร่วมกับคำสั่งการเพิ่ม หรือการลบเกี่ยวกับวันที่
เช่น add() sub() รูปแบบการใช้งาน DateInterval
 
$date = new DateTime("2022-12-29"); //2022-12-29 00:00:00
$interval = new DateInterval("P1D");
$date->add($interval); // +1 วัน
echo $date->format('Y-m-d H:i:s'); // 2022-12-30 00:00:00
// $date ค่าเปลี่ยนแปลงไปแล้ว ตอนนี้คือ 2022-12-30
$date->sub($interval); // -1 วัน
echo $date->format('Y-m-d H:i:s'); // 2022-12-29 00:00:00
 
ในตัวอย่าง เรากำหนดวันที่เป็น 29 และกำหนดระยะเวลาเป็นรูปแบบ "P1D" (จะอธิบายการใช้งาน
รูปแบบด้านล่างเพิ่มเติม) ซึ่งก็คือ 1 วัน ดังนั้นเมื่อเราเพิ่มระยะเวลาเข้าไปในเวลาที่กำหนด 1 วัน
ด้วยคำสั่ง add() วันใหม่ก็เป็น 30  และเมื่อเราลบเวลาที่กำหนด 1 วัน ด้วยคำสั่ง sub() ก็จะได้
วันใหม่เป็น 29 
 

รูปแบบข้อความที่กำหนดใน DateInterval() เราจะใช้รูปแบบอักษรย่อดังนี้
 

จะเริ่มต้นด้วยตัว P ตัวใหญ่เสมอ กรณีมีเวลาด้วย จะมีตัว T เพิ่มคั่นกับเวลา โดยมีรูปแบบย่อ ดังนี้

Y - years
M - months
D - days
W - weeks. ก่อน PHP 8.0.0, จะไม่สามารถใช้ร่วมกับตัว D ได้.
H - hours
M - minutes
S - seconds
 
ตัวอย่างเช่น 
 
1 ปี 3 เดือน 2 วัน 30 นาที ก็จะได้เป็น 
"P1Y3M2DT30M"
 
$date = new DateTime("2022-12-29"); //2022-12-29 00:00:00
$interval = new DateInterval("P1Y3M2DT30M");
$date->add($interval); // +1 ปี 3 เดือน 2 วัน 30 นาที
echo $date->format('Y-m-d H:i:s'); // 2024-03-31 00:30:00
 
5 ชั่วโมง 45 นาที ก็จะได้เป็น
"PT5H45M"
 
$date = new DateTime("2022-12-29"); //2022-12-29 00:00:00
$interval = new DateInterval("PT5H45M");
$date->add($interval); // +5 ชั่วโมง 45 นาทีี
echo $date->format('Y-m-d H:i:s'); // 2022-12-29 05:45:00
 
เราสามารถแปลงค่า ระยะเวลาของ DateInterval เป็นข้อความตัวเลขข้อมูลที่ต้องการได้ ดังนี้
 
$interval = new DateInterval("P2YT5H45M");
echo $interval->format("%y ปี %h ชั่วโมง %i นาที");
// 2 ปี 5 ชั่วโมง 45 นาที
 
 

การเปลี่ยนแปลงแก้ไขวันที่
 

การเปลี่ยนแปลงแก้ไขวันที่ไม่ว่าจะเป็นการเพิ่มหรือการลบ นอกจากจะใช้งาน DateInterval ร่วม
กับคำสั่ง add() หรือ sub() แล้ว เรายังสามารถใช้งานคำสั่ง modify() โดยส่งรูปแบบข้อความ
ที่ต้องการเข้าไป เพื่อกำหนดระยะเวลาที่ต้องการได้ 
 
$date = new DateTime("2022-12-29"); //2022-12-29 00:00:00
$date->modify("+1 year +3 month +2 day +30 minute");
echo $date->format('Y-m-d H:i:s'); // 2024-03-31 00:30:00
 
จะเห็นว่าเราสามารถกำหนด เครื่องหมาย + สำหรับการเพิ่ม และเครื่องหมาย - สำหรับการลบเวลา
ข้อความ String เกี่ยวกับวันที่ต่างๆ ดูเพิ่ม http://niik.in/800
 
 

การจัดการวันที่ 2 วันที่ หรือ ระหว่างวันที่ ด้วย DateTime

ใน DateTime object เราสามารถหาระยะห่างของเวลา 2 เวลาด้วยคำสั่ง diff()
 
$originalTime = new DateTime();
$targedTime = new DateTime("1999-07-20");
echo $originalTime->format('Y-m-d H:i:s'); // 2022-12-27 15:06:33
echo $targedTime->format('Y-m-d H:i:s'); // 1999-07-20 00:00:00
$interval = $originalTime->diff($targedTime);
echo $interval->format("%R %y %m %d %h %i %s %a");
// - 23 5 7 15 8 37 8561
// %R สำหรับหาว่าค่าในคำสั่ง diff() หรือค่า target เป็น + หรือ - ถ้า - คือน้อยกว่าอีกค่า
// ถ้าเป็น + คือมากกว่าอีกค่า สามารถใช้ %r แทนก็ได้กรณีค่ามากกว่าไม่ต้องแสดงเครื่องหมาย +
// สำหรับ %a จะหมายถึงค่าระยะเวลาทั้งหมด คิดเป็นวัน อย่างข้างต้นก็คือ 8561 วัน
// ส่วนค่าอื่นๆ ก็จะเป็น ปี เดือน วัน ชั่วโมง นาที วินาที ที่ต่างกัน
 
เราลองมาทดสอบหาค่าง่ายๆ เช่น ห่างกันแค่ 1 วันดูว่าจะเป็นในลักษณะใด
 
$originalTime = new DateTime("2022-12-27");
$targedTime = new DateTime("2022-12-28");
echo $originalTime->format('Y-m-d H:i:s'); // 2022-12-27 00:00:00
echo $targedTime->format('Y-m-d H:i:s'); // 2022-12-28 00:00:00
$interval = $originalTime->diff($targedTime);
echo $interval->format("%R %y %m %d %h %i %s %a");
//+ 0 0 1 0 0 0 1
// ค่า target มากกว่า 1 วัน
 
เราสามารถประยุกต์หาอายุ อย่างง่ายได้ดังนี้
 
$originalTime = new DateTime("now midnight");
$targedTime = new DateTime("1999-07-20 midnight");
echo $originalTime->format('Y-m-d H:i:s'); // 2022-12-27 00:00:00
echo $targedTime->format('Y-m-d H:i:s'); // 1999-07-20 00:00:00
$interval = $originalTime->diff($targedTime);
echo $interval->format("อายุ %y ปี %m เดือน %d วัน");
//อายุ 23 ปี 5 เดือน 7 วัน
 
 

การสร้างชุดข้อมูลช่วงวันที่หรือเวลาด้วย DatePeriod 

กรณีที่เราต้องการชุดข้อมูลช่วงเวลาสำหรับไปใช้งานหรือแสดง เช่น สร้างเป็นลิสรายการวันที่
ของเดือนใดๆ ก็สามารถใช้ DatePeriod ได้ดังนี้
 
$start = new DateTime('first day of this month midnight');
$end   = new DateTime('first day of next month midnight');
echo $start->format('Y-m-d H:i:s'); // 2022-12-01 00:00:00
echo $end->format('Y-m-d H:i:s'); // 2023-01-01 00:00:00
$interval = new DateInterval('P1D'); // ระยะเวลาห่างกัน 1 วัน
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $dt) {
	echo $dt->format("Y-m-d")."<br>";
}

// วนลูปแสดงวันที่ 1 ถึงวันสิ้นเดือนของเดือนปัจจุบัน
// เนื่องจากรูปแบบการใช้งานข้างต้นใน PHP ที่ไม่ใช่เวอร์ชั่นที่ 8.2 จะไม่มี 
// DatePeriod::INCLUDE_END_DATE หรือไม่รวมวันที่สุดท้ายในค่าเริ่มต้น 
// การกำหนดวันสุดท้ายของเดือน จึงใช้เป็นการกำหนดวันแรกของเดือนถัดไปแทน เพื่อ
// ให้รวมวันสุดท้ายของเดือนเข้ามาด้วย

// กรณีเป็น PHP เวอร์ชั่น 8.2 เราสามารถกำหนดแบบนี้แทนได้

$start = new DateTime('first day of this month midnight');
$end   = new DateTime('last day of this month midnight');
echo $start->format('Y-m-d H:i:s'); // 2022-12-01 00:00:00
echo $end->format('Y-m-d H:i:s'); // 2022-12-31 00:00:00
$interval = new DateInterval('P1D'); // ระยะเวลาห่างกัน 1 วัน
$period = new DatePeriod($start, $interval, $end, 
				DatePeriod::INCLUDE_END_DATE);
 
เราสามารถใช้งาน DatePeriod โดยแทนที่จะกำหนด วันสิ้นสุดหรือ $end ก็กำหนดเป็นจำนวนครั้งของ
การทำซ้ำ หรือที่เรียกว่า recurrences แทนได้ สมมติเช่น เราต้องการแสดงเดือน ทุกเดือนในปีนี้ หรือก็
คือต้องการแสดงวันที่ 1 ของทุกเดือน ให้เลือก ก็กำหนดวันเริ่มต้นเป็นวันที่ 1 และเป็นค่าวันที่ที่เราจะใช้ 
จากนั้นเรากำหนดระยะเวลาทำซ้ำเป็น ทุกๆ 1 เดือน และสุดท้ายกำหนดจำนวนที่ทำซ้ำ เนื่องจาก เรามีค่า
แรกแล้วดังนั้น 12 เดือน เราต้องทำซ้ำอีกทั้งหมด 11 ครั้ง ก็จะได้เป็นดังนี้
 
$start = new DateTime('first day of january midnight');
echo $start->format('Y-m-d H:i:s'); // 2022-01-01 00:00:00
$interval = new DateInterval('P1M'); // ระยะเวลา 1 เดือน
$recurrences = 11; // ทำซ้ำ 11 ครั้ง
$period = new DatePeriod($start, $interval, $recurrences);
foreach ($period as $dt) {
	echo $dt->format("Y-m")."<br>";
}
// ผลลัพธ์เราก็ไจะได้วันที่ 1 ของแต่ละเดือน ในปีนั้นๆ มาใช้งานได้
// ถ้าต้องการแสดงแค่ 3 เดือน 6 เดือน 9 เดือน ก็แค่เปลี่ยนตัวเลขจำนวนการทำซ้ำ ตามต้องการ
// ข้อสังเกต ระยะเวลาที่กำหนดด้วย "P1M" ระบบจะพิจารณาตามวันที่จริง เพราะข้อมูลช่วงของ
// วันที่จะต้องเป็นช่วงเวลาจริงๆ แต่ถ้าเราต้องการ วันที่ตามจำนวนวัน เช่น กรณี กำหนดผ่อนชำระ
// ทุกๆ 30 วัน และกำหนดเป็น "P30D" ค่าที่ได้จะนับเป็นวัน บางเดือนอาจจะมี 2 ค่าก็ได้ เช่น
// วันที่ 1 และอีก 30 วันก็เป็นวันที่ 31 ดูตัวอย่างด้านล่าง

$start = new DateTime('first day of january midnight');
echo $start->format('Y-m-d H:i:s'); // 2022-01-01 00:00:00
$interval = new DateInterval('P30D'); // ทุกๆ 30 วัน
$recurrences = 12; // รวม 12 รอบบิล
// เราไม่รวมวันที่แรกหรือวันที่ 1 กำหนด้วย DatePeriod::EXCLUDE_START_DATE
$period = new DatePeriod($start, $interval, $recurrences, 
				DatePeriod::EXCLUDE_START_DATE);
foreach ($period as $dt) {
	echo $dt->format("Y-m-d")."<br>";
}
ผลลัพธ์ที่ได้ สังเกตว่าเดือน 5 จะมี 2วันคือวันที่ 1 กับวันที่ 31 ซึ่งห่างกัน 30 วัน

2022-01-31
2022-03-02
2022-04-01
2022-05-01
2022-05-31
2022-06-30
2022-07-30
2022-08-29
2022-09-28
2022-10-28
2022-11-27
2022-12-27
 
เนื้อหาในบทความนี้ เราได้รู้เพิ่มเติมเกี่ยวกับการใช้งานวันที่และเวลาใน PHP สามารถเอาไปใช้
เป็นแนวทางประยุกต์เพิ่มเติมได้ หรือนำไปใช้งานร่วมกับคำสั่งอื่นๆ เกี่ยวกับเวลาแทนได้ หวังว่าจะ
เป็นประโยชน์ไม่มากก็น้อย *บทความแรกของปีนี้ 


กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ







เนื้อหาที่เกี่ยวข้อง









URL สำหรับอ้างอิง





คำแนะนำ และการใช้งาน

สมาชิก กรุณา ล็อกอินเข้าระบบ เพื่อตั้งคำถามใหม่ หรือ ตอบคำถาม สมาชิกใหม่ สมัครสมาชิกได้ที่ สมัครสมาชิก


  • ถาม-ตอบ กรุณา ล็อกอินเข้าระบบ
  • เปลี่ยน


    ( หรือ เข้าใช้งานผ่าน Social Login )







เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ