เราได้เคยรู้จักการจัดการวันที่และเวลาใน php ด้วย strtotime() ฟังก์ชั่นไปแล้วในบทความ
ก่อนหน้า เนื้อหานี้ เราจะมาเพิ่มเติมการจัดการวันที่และเวลาด้วยความสามารถของ DateTime
object ที่มีมาให้ใน php
การใช้งานรูปแบบข้อความวันที่และเวลา กับฟังก์ชั่น strtotime() ใน php http://niik.in/800
https://www.ninenik.com/content.php?arti_id=800 via @ninenik
โดยในเนื้อหานี้จะพยายามนำเอาความสามารถและประโยชน์ต่างๆ ที่จะได้รับเมื่อนำมาปรับใช้งาน
ดูเนื้อหาอ้างอิงได้ที่ https://www.php.net/manual/en/book.datetime.php
DateTime class เป็น class ที่เราสามารถใช้ในการจัดการวันที่และเวลา ไม่ว่าจะโดยการส่งค่า
ข้อความ หรือใช้ค่าจากระบบในการสร้างรูปแบบวันที่ขึ้นมาใช้งาน
การจัดการวันที่และเวลาบางกรณีเวลาของ server อาจจะไม่ตรง ซึ่งอาจจะเป็นเพราะการกำหนด
timezone ของระบบ ดังนั้นเราอาจจะต้องกำหนด ค่านี้ไว้ในส่วนบนสุดของไฟล์ php หรืออาจจะ
ตั้งค่าให้ server เพียงครั้งเดียวก็ได้
การกำหนด timezone ในไฟล์ php
1 2 3 | <?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 การใช้งานที่ไม่แตกต่างกันมากนัก
ดูตัวอย่างเปรียบเทียบความแตกต่าง
1 2 3 4 5 6 | // ถ้าวันนี้วันที่ 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() จะไม่มีการเปลี่ยนแปลง ดังนี้
1 2 3 4 5 | $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
1 2 3 4 | $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 ได้ ตัวอย่างเช่าน
1 2 3 4 5 | // ถ้าวันนี้วันที่ 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
1 2 3 4 5 6 7 | $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"
1 2 3 4 | $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"
1 2 3 4 | $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 เป็นข้อความตัวเลขข้อมูลที่ต้องการได้ ดังนี้
1 2 3 | $interval = new DateInterval( "P2YT5H45M" ); echo $interval ->format( "%y ปี %h ชั่วโมง %i นาที" ); // 2 ปี 5 ชั่วโมง 45 นาที |
การเปลี่ยนแปลงแก้ไขวันที่
การเปลี่ยนแปลงแก้ไขวันที่ไม่ว่าจะเป็นการเพิ่มหรือการลบ นอกจากจะใช้งาน DateInterval ร่วม
กับคำสั่ง add() หรือ sub() แล้ว เรายังสามารถใช้งานคำสั่ง modify() โดยส่งรูปแบบข้อความ
ที่ต้องการเข้าไป เพื่อกำหนดระยะเวลาที่ต้องการได้
1 2 3 | $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()
1 2 3 4 5 6 7 8 9 10 11 | $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 วันดูว่าจะเป็นในลักษณะใด
1 2 3 4 5 6 7 8 | $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 วัน |
เราสามารถประยุกต์หาอายุ อย่างง่ายได้ดังนี้
1 2 3 4 5 6 7 | $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 ได้ดังนี้
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $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 ครั้ง ก็จะได้เป็นดังนี้
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $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 สามารถเอาไปใช้
เป็นแนวทางประยุกต์เพิ่มเติมได้ หรือนำไปใช้งานร่วมกับคำสั่งอื่นๆ เกี่ยวกับเวลาแทนได้ หวังว่าจะ
เป็นประโยชน์ไม่มากก็น้อย *บทความแรกของปีนี้