Bagaimana cara menunjukkan tanggal di zona waktu yang benar?

18

Saya memiliki bidang Rentang Datetime (field_date) dalam tipe konten. Setelah saya membuat jenis konten saya, saya menetapkan Tanggal Mulai sebagai:

2017-02-27 19:30:01

masukkan deskripsi gambar di sini

Sekarang saya ingin mendapatkan nilai dan menampilkan tanggal dalam format lain, jadi coba gunakan kode berikut:

// 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);

Ini adalah output saya:

// 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

Jadi, bagaimana cara menunjukkan tanggal di zona waktu yang benar?

Adrian Cid Almaguer
sumber

Jawaban:

21

Saya menduga masalahnya ada hubungannya dengan beberapa nuansa strtotime().

strtotime()dapat mengambil sembarang string, dan mengubahnya menjadi cap waktu Unix. Masalahnya adalah bahwa ketika string tidak mengandung zona waktu eksplisit, itu akan menggunakan apa yang ditetapkan oleh date_default_timezone_get(). Itu harus ditetapkan dari pengguna saat ini, (itu diatur oleh proksi akun). Namun, string yang Anda tarik $node->field_date->valuesecara implisit dalam UTC. Dengan kata lain, saya pikir string sedang diurai oleh strtotime()sedang ditafsirkan sebagai di 'Amerika / New_York' dan bukan 'UTC'.

Kabar baiknya adalah Anda dapat menyederhanakan situasi Anda banyak. Item bidang untuk rentang tanggal terdiri dari empat bagian

  • 'value' adalah tanggal mulai sebagai string dalam UTC
  • 'start_date' adalah objek DrupalDateTime yang mewakili 'nilai'
  • 'end_value' adalah tanggal akhir sebagai string dalam UTC
  • 'end_date' adalah objek DrupalDateTime yang mewakili 'end_value'

Untuk bidang waktu tanggal polos mereka

  • 'value' adalah tanggal sebagai string dalam UTC
  • 'date' adalah objek DrupalDateTime yang mewakili 'nilai'

Jadi, Anda bisa bekerja dengan DrupalDateTime()objek secara langsung. Selain itu, date.formatterlayanan itu harus menggunakan zona waktu yang tepat yang digunakan oleh pengguna melihat halaman secara default (selain menggunakan bahasa aktif pengguna).

Saya kira sesuatu seperti ini akan berhasil

$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'
);

Catatan saya menambahkan placeholder format 'P' di sana sehingga Anda dapat melihat zona waktu apa yang digunakan sistem.

Pastikan Anda memiliki pengaturan zona waktu yang tepat di admin / config / regional / pengaturan, dan zona waktu pengguna Anda sesuai dengan yang Anda harapkan. Juga pastikan bahwa Anda memiliki zona waktu yang tepat di php.ini Anda (ini adalah date.timezonepengaturannya); hal-hal aneh terjadi ketika ini tidak disetel (Dan jauh di atas kepala saya, saya tidak ingat apakah itu menyebabkan peringatan di installer atau pada laporan status ketika tidak disetel. Saya ingat masalah ini, tetapi tidak masalah apakah itu didapat berkomitmen).

mpdonadio
sumber
1
@mpdonadio Terima kasih atas bantuannya! Saya tidak tahu tentang datefitur untuk mengakses DrupalDateTime. Karena penasaran bagaimana Anda mengetahui hal ini? Saya bisa mengetahui bahwa bidang saya adalah tipe DateTimeItemtetapi dalam sana tidak tampak jelas bahwa ada date(atau value) anggota publik untuk kelas itu.
Pzanno
1
@Pzanno Saya adalah co-maintainer Drupal 8 core datetime.module, dan juga banyak hal terkait tanggal / waktu inti lainnya yang saya dapatkan :) Properti-properti tersebut adalah metode ajaib. Jika Anda melihat DateTimeItem::propertyDefinitions(), Anda akan melihat apa yang terbuka. Kemudian lihat DateTimeComputed::getValue()untuk melihat bagaimana itu bekerja. Semua kelas Item dapat diperiksa dengan cara itu, tetapi hanya sedikit yang menggunakan nilai yang dihitung. Saya berharap ada cara yang lebih baik untuk mengekspos ini ke API.
mpdonadio
@mpdonadio terima kasih atas penjelasannya! Saya melewatkan fakta bahwa mereka bahkan didefinisikan dalam DateTimeItem::propertyDefinitions(). Saya pikir ada beberapa metode ajaib yang terjadi, tetapi ingin memahami bagaimana ini dibuat sehingga saya bisa lebih memahami cara mengakses bidang lain juga. Seperti yang Anda katakan, alangkah baiknya jika API dibuka, tetapi ini membantu. Terima kasih lagi.
Pzanno
1
Dalam kasus saya, saya harus melakukannya $node->field_date->date, bukan $node->field_date->start_date.
Marcos Buarque
2
Mendukung tanggapan ini karena ini adalah bagian paling informatif dari dokumentasi Drupal yang pernah saya temukan.
Ryan H
6

Berbasis di Menangani konversi zona waktu dengan PHP DateTime saya mengubah kode saya menjadi ini:

$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);

Dan sekarang tanggal keluaran saya baik-baik saja:

2017-02-27 19:30:01

Ini bekerja. Tapi saya yakin ada cara untuk melakukan ini menggunakan Drupal API.

Adrian Cid Almaguer
sumber
1
Saya menghapus komentar saya sebelumnya. DrupalDateTime tidak menyesuaikan zona waktu pengguna Drupal.
oknate
Dalam kasus saya, saya hanya menggunakan ini sebelum panggilan fungsi tanggal:date_default_timezone_set(drupal_get_user_timezone());
Roger
Terima kasih untuk ini. Itu sangat membantu saya dengan drupal.stackexchange.com/q/256490/2089 .
colan
@olan senang membantu Anda, jika Anda berpikir bahwa jawaban saya berguna saya pikir Anda dapat memeriksa jawaban yang lain juga.
Adrian Cid Almaguer
4

Saya biasanya menyelesaikannya dengan cara ini .:

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 );
Ytacol
sumber
2

Ini bekerja untuk saya:

// 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");
Dan Poenaru
sumber
Ini juga berfungsi untuk saya `$ dDate = DrupalDateTime :: createFromTimestamp ($ form_state-> getValue ('service_date') -> getTimestamp (), 'UTC'); // Gunakan seperti ini. $ dDate-> format ('Ymd \ TH: i: s'); `
Yogesh Kushwaha
1

Kode ini berfungsi untuk saya.

// 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');
Arun Mishra
sumber
0

Tidak satu pun dari jawaban lain ini yang berhasil untuk saya. Inilah yang akhirnya saya dapatkan dengan:

$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');
pengguna1359
sumber
0

Saya menggunakan cuplikan ini untuk bekerja dengan tanggal:

<?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());
    }
}

Anda bisa mendapatkan informasi lebih lanjut tentang objek Datetime di sini

Ben Cassinat
sumber