วิธีการแสดงวันที่ในเขตเวลาที่ถูกต้อง?


18

ฉันมีเขตข้อมูลช่วงเวลาที่ใช้งาน (field_date) ในประเภทเนื้อหา เมื่อฉันสร้างประเภทเนื้อหาของฉันฉันตั้งวันที่เริ่มเป็น:

2017-02-27 19:30:01

ป้อนคำอธิบายรูปภาพที่นี่

ตอนนี้ฉันต้องการรับค่าและแสดงวันที่ในรูปแบบอื่นดังนั้นให้ลองใช้รหัสต่อไปนี้:

// Loading the node.
$node = Node::load(2100);
// Getting the start date value.
$date = $node->field_date->value;
// Printing to see what is the output.
dpm($node->field_date->value);
$date = strtotime($date);
// Printing my timezone.
dpm(drupal_get_user_timezone());
// Applying my custom format.
$date = \Drupal::service('date.formatter')->format($date, 'custom', 'Y-m-d H:i:s', drupal_get_user_timezone());
// Printing to see the output.
dpm($date);

นี่คือผลลัพธ์ของฉัน:

// It's fine.
2017-02-28T00:30:01
// Its fine.
America/New_York
// This is not what I waiting for. I'm waiting here: 2017-02-27 19:30:01
2017-02-28 00:30:01

ดังนั้นจะแสดงวันที่ในเขตเวลาที่ถูกต้องได้อย่างไร

คำตอบ:


21

ฉันสงสัยว่าปัญหาเกี่ยวข้องกับความแตกต่างของstrtotime()บางอย่าง

strtotime()สามารถใช้สตริงใดก็ได้และแปลงเป็น Unix Timestamp date_default_timezone_get()ปัญหาคือว่าเมื่อสตริงไม่ประกอบด้วยเขตอย่างชัดเจนก็จะใช้สิ่งที่ถูกกำหนดโดย ที่ควรตั้งค่าจากผู้ใช้ปัจจุบันแม้ว่า (มันถูกกำหนดโดยพร็อกซี่บัญชี) อย่างไรก็ตามสตริงที่คุณกำลังดึงออกมา$node->field_date->valueจะอยู่ใน UTC โดยปริยาย ในคำอื่น ๆ ฉันคิดว่าสตริงจะถูกแยกวิเคราะห์โดยstrtotime()จะถูกตีความเช่นเดียวกับใน 'America / New_York' และไม่ใช่ 'UTC'

ข่าวดีก็คือคุณสามารถทำให้สถานการณ์ของคุณง่ายขึ้นมาก รายการฟิลด์สำหรับช่วงวันที่ประกอบด้วยสี่ส่วน

  • 'value' คือวันที่เริ่มต้นเป็นสตริงใน UTC
  • 'start_date' เป็นวัตถุ DrupalDateTime แทน 'value'
  • 'end_value' คือวันที่สิ้นสุดเป็นสตริงใน UTC
  • 'end_date' เป็นวัตถุ DrupalDateTime แทน 'end_value'

สำหรับเขตเวลาวันที่ธรรมดาพวกเขา

  • 'value' คือวันที่เป็นสตริงใน UTC
  • 'date' เป็นวัตถุ DrupalDateTime แทน 'value'

ดังนั้นคุณสามารถทำงานกับDrupalDateTime()วัตถุได้โดยตรง นอกจากนี้date.formatterบริการดังกล่าวควรดึงเขตเวลาที่เหมาะสมในการใช้งานโดยผู้ใช้ที่ดูหน้าเว็บเป็นค่าเริ่มต้น (นอกเหนือจากการใช้ภาษาที่ใช้งานของผู้ใช้)

ฉันสงสัยว่าสิ่งนี้จะได้ผล

$node = Node::load(2100);
$start_date = $node->field_date->start_date;
$formatted = \Drupal::service('date.formatter')->format(
  $start_date->getTimestamp(), 'custom', 'Y-m-d H:i:s P'
);

หมายเหตุฉันได้เพิ่มตัวยึดรูปแบบ 'P' ไว้ที่นั่นเพื่อให้คุณสามารถดูว่าเขตเวลาใดที่ระบบคิดว่าใช้งานอยู่

ตรวจสอบให้แน่ใจว่าคุณได้ตั้งค่าเขตเวลาที่เหมาะสมบน admin / config / region / settings และเขตเวลาผู้ใช้ของคุณเป็นสิ่งที่คุณคาดหวัง ตรวจสอบให้แน่ใจว่าคุณมีการตั้งค่าเขตเวลาที่เหมาะสมใน php.ini ของคุณ (เป็นการdate.timezoneตั้งค่า) สิ่งแปลก ๆ เกิดขึ้นเมื่อไม่ได้ตั้งค่า (และด้านบนของหัวของฉันฉันจำไม่ได้ว่าถ้านั่นทำให้เกิดการเตือนในตัวติดตั้งหรือรายงานสถานะเมื่อไม่ได้ตั้งค่าฉันจำปัญหาได้ แต่ไม่ใช่ว่ามันจะได้รับ มุ่งมั่น).


1
@mpdonadio ขอบคุณสำหรับความช่วยเหลือ! ฉันไม่รู้เกี่ยวกับdateคุณสมบัติในการเข้าถึง DrupalDateTime จากความอยากรู้คุณคิดออกยังไง? ฉันสามารถคิดออกได้ว่าฟิลด์ของฉันเป็นแบบนั้นDateTimeItemแต่ภายในนั้นดูเหมือนจะไม่ชัดเจนว่ามีสมาชิกสาธารณะdate(หรือvalue) สำหรับชั้นเรียนนั้น
Pzanno

1
@Pzanno ฉันเป็น Drupal 8 หลัก datetime.module ผู้ดูแลร่วมกันและยังมีอีกหลายสิ่งที่เกี่ยวข้องกับวันที่ / เวลาหลักมาทางของฉัน :) คุณสมบัติเป็นวิธีการที่วิเศษ หากคุณดูDateTimeItem::propertyDefinitions()คุณจะเห็นสิ่งที่สัมผัส จากนั้นดูที่DateTimeComputed::getValue()วิธีการใช้งาน คลาสไอเท็มทั้งหมดสามารถตรวจสอบได้ด้วยวิธีนี้ แต่มีเพียงค่าที่คำนวณได้จำนวนหนึ่ง ฉันหวังว่าจะมีวิธีที่ดีกว่าในการเปิดเผยสิ่งนี้กับ API
mpdonadio

@mpdonadio ขอบคุณสำหรับคำอธิบาย! DateTimeItem::propertyDefinitions()ฉันคิดถึงความจริงที่ว่าพวกเขาถูกกำหนดไว้แม้ใน ฉันคิดว่ามีวิธีเวทมนต์เกิดขึ้น แต่ต้องการที่จะเข้าใจว่าสิ่งเหล่านี้ถูกสร้างขึ้นอย่างไรเพื่อให้ฉันสามารถเข้าใจวิธีการเข้าถึงสาขาอื่น ๆ ได้ดีขึ้น อย่างที่คุณบอกว่ามันจะดีถ้า API ถูกเปิดเผย แต่สิ่งนี้จะช่วยได้ ขอบคุณอีกครั้ง.
Pzanno

1
ในกรณีของฉันที่ฉันต้องทำแทน$node->field_date->date $node->field_date->start_date
Marcos Buarque

2
อุปกรณ์ประกอบฉากในการตอบสนองนี้เป็นเอกสารที่มีข้อมูลมากที่สุดของ Drupal ที่ฉันเคยพบ
Ryan H

6

จากการจัดการการแปลงเขตเวลาด้วย PHP DateTimeฉันปรับเปลี่ยนรหัสของฉันเป็น:

$node = Node::load(2100);
$userTimezone = new DateTimeZone(drupal_get_user_timezone());
$gmtTimezone = new DateTimeZone('GMT');
$myDateTime = new DateTime($node->field_date->value, $gmtTimezone);
$offset = $userTimezone->getOffset($myDateTime);
$myInterval = DateInterval::createFromDateString((string)$offset . 'seconds');
$myDateTime->add($myInterval);
$result = $myDateTime->format('Y-m-d H:i:s');
dpm($result);

และตอนนี้วันที่ส่งออกของฉันมันไม่เป็นไร:

2017-02-27 19:30:01

วิธีนี้ใช้ได้ผล แต่ฉันแน่ใจว่ามีวิธีการทำเช่นนี้โดยใช้ Drupal API


1
ฉันลบความคิดเห็นก่อนหน้าของฉัน DrupalDateTime ไม่ได้ปรับสำหรับเขตเวลาของผู้ใช้ Drupal
ตกลง

ในกรณีของฉันฉันเพิ่งใช้สิ่งนี้ก่อนที่จะเรียกใช้ฟังก์ชันวันที่:date_default_timezone_set(drupal_get_user_timezone());
Roger

ขอบคุณสำหรับสิ่งนี้. จริงๆมันช่วยฉันด้วยdrupal.stackexchange.com/q/256490/2089
colan

@ มีความสุขช่วยให้คุณถ้าคุณคิดว่าคำตอบของฉันมีประโยชน์ฉันคิดว่าคุณสามารถตรวจสอบคำตอบอื่น ๆ ได้เช่นกัน
Adrian Cid Almaguer

4

ฉันมักจะแก้ปัญหาแบบนี้:

node = Node::load(1);    
$date_original= new DrupalDateTime( $node->field_date->value , 'UTC' );     
$result = \Drupal::service('date.formatter')->format( $date_original->getTimestamp(), 'custom', 'Y-m-d H:i:s'  );    
dpm( $result );

2

สิ่งนี้ใช้ได้กับฉัน:

// Take the timestamp.
$timestamp = $form_state->getValue($form_field)->getTimestamp();
// Convert to UTC - the way its saved in database.
$date = DrupalDateTime::createFromTimestamp($timestamp, 'UTC');
// Add on the current entity.
$this->entity->{$db_field}->value = $date->format("Y-m-d\TH:i:s");

มันทำงานได้ดีสำหรับฉันเช่นกัน `$ dDate = DrupalDateTime :: createFromTimestamp ($ form_state-> getValue ('service_date') -> getTimestamp (), 'UTC'); // ใช้แบบนี้ $ dDate-> format ('Ymd \ TH: i: s'); `
Yogesh Kushwaha

1

รหัสนี้ใช้งานได้สำหรับฉัน

// set use timezone
userTimezone = new DateTimeZone(drupal_get_user_timezone());
// set gmt timezone
$gmtTimezone = new DateTimeZone('GMT');
// Take the timestamp.
$start_date = $val['field_start_time_value'];    
$startDateTime = new DateTime($start_date, $gmtTimezone);
$offset = $userTimezone->getOffset($startDateTime);
$startInterval = DateInterval::createFromDateString((string)$offset . 'seconds');
$startDateTime->add($startInterval);
$result = $startDateTime->format('Y-m-d H:i:s');

0

ไม่มีคำตอบอื่นใดที่เหมาะกับฉัน นี่คือสิ่งที่ฉันท้ายที่สุดด้วย:

$range_start = DrupalDatetime::createFromTimestamp((int)$start_date); // unix timestamp
$range_start->setTimezone(new \Datetimezone('EST'));
$node->field_date_range->value = format_date(
  $range_start->getTimestamp() , 'custom', 'Y-m-d\TH:i:s', 'EST');

0

ฉันใช้ตัวอย่างนี้เพื่อทำงานกับวันที่:

<?php
class MyApp extends ControllerBase
{
    public function output() 
    {
        $dtime = DateTime::createFromFormat("d/m/Y - H:I:s", "22/12/1999 - 22:55:12", $this->getDateTimeZone());
        $time = $dtime->format('r');
        // My code goes here
    }

    private function getDateTimeZone()
    {
        return new DateTimeZone(drupal_get_user_timezone());
    }
}

คุณสามารถรับข้อมูลเพิ่มเติมเกี่ยวกับวัตถุ Datetime ได้ที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.