Come mostrare una data nel fuso orario corretto?


19

Ho un campo Intervallo datetime (field_date) in un tipo di contenuto. Una volta creato il mio tipo di contenuto, ho impostato la Data di inizio come:

27/02/2017 19:30:01

inserisci qui la descrizione dell'immagine

Ora voglio ottenere il valore e mostrare la data in un altro formato, quindi prova a utilizzare il seguente codice:

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

Questa è la mia uscita:

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

Quindi, come mostrare una data nel fuso orario corretto?

Risposte:


22

Sospetto che il problema abbia a che fare con alcune sfumature di strtotime().

strtotime()può prendere praticamente qualsiasi stringa e convertirla in un timestamp Unix. Il problema è che quando la stringa non contiene un fuso orario esplicito, utilizzerà ciò che è impostato da date_default_timezone_get(). Questo dovrebbe essere impostato dall'utente corrente, tuttavia (è impostato dal proxy dell'account). Tuttavia, la stringa che stai estraendo $node->field_date->valueè implicitamente in UTC. In altre parole, penso che la stringa che viene analizzata strtotime()venga interpretata come in "America / New_York" e non "UTC".

La buona notizia è che puoi semplificare molto la tua situazione. L'elemento del campo per un intervallo di date è composto da quattro parti

  • 'valore' è la data di inizio come stringa in UTC
  • 'start_date' è un oggetto DrupalDateTime che rappresenta 'valore'
  • 'end_value' è la data di fine come stringa in UTC
  • 'end_date' è un oggetto DrupalDateTime che rappresenta 'end_value'

Per un semplice campo data e ora lo sono

  • 'valore' è la data come stringa in UTC
  • 'date' è un oggetto DrupalDateTime che rappresenta 'valore'

Quindi, puoi lavorare DrupalDateTime()direttamente con l' oggetto. Inoltre, tale date.formatterservizio dovrebbe richiamare il fuso orario corretto utilizzato dall'utente che visualizza la pagina per impostazione predefinita (oltre a utilizzare la lingua attiva dell'utente).

Sospetto che qualcosa del genere funzionerà

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

Nota Ho aggiunto il segnaposto in formato 'P' lì in modo da poter vedere quale fuso orario il sistema pensa sia in uso.

Assicurati di avere il fuso orario corretto impostato su admin / config / regional / settings e che il fuso orario dell'utente sia quello che ti aspetti. Assicurati anche di avere il fuso orario corretto nel tuo php.ini (è l' date.timezoneimpostazione); accadono cose strane quando questo non è impostato (e dalla parte superiore della mia testa, non ricordo se ciò provoca un avviso nell'installer o sul rapporto di stato quando non impostato. Ricordo il problema, ma non se ha ottenuto commesso).


1
@mpdonadio Grazie per l'aiuto! Non sapevo della datefunzione per accedere a DrupalDateTime. Per curiosità come l'hai capito? Sono stato in grado di capire che il mio campo era del tipo DateTimeItemma al suo interno non sembra ovvio che ci sia un date(o value) membro pubblico per quella classe.
Pzanno

1
@Pzanno Sono il co-maintainer principale di Drupal 8 datetime.module, e anche molte altre cose relative a data / ora vengono dalla mia strada :) Le proprietà sono metodi magici. Se guardi DateTimeItem::propertyDefinitions(), vedrai cosa è esposto. Quindi guarda DateTimeComputed::getValue()per vedere come funziona. Tutte le classi di oggetti possono essere esaminate in questo modo, ma solo una manciata utilizza valori calcolati. Vorrei che ci fosse un modo migliore per esporre questo all'API.
mpdonadio

@mpdonadio grazie per la spiegazione! Mi mancava il fatto che fossero persino definiti DateTimeItem::propertyDefinitions(). Ho pensato che stessero accadendo alcuni metodi magici, ma volevo capire come sono stati creati in modo da poter capire meglio come accedere anche ad altri campi. Come hai detto, sarebbe bello se l'API fosse esposta, ma questo aiuta. Grazie ancora.
Pzanno

1
Nel mio caso, ho dovuto fare $node->field_date->date, invece di $node->field_date->start_date.
Marcos Buarque,

2
Sostieni questa risposta in quanto questo è il pezzo più informativo della documentazione di Drupal che abbia mai trovato.
Ryan H,

6

Basato sulla gestione della conversione del fuso orario con PHP DateTime ho modificato il mio codice in questo modo:

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

E ora la mia data di uscita va bene:

2017-02-27 19:30:01

Questo funziona Ma sono sicuro che c'è un modo per farlo usando l'API Drupal.


1
Ho rimosso il mio commento precedente. DrupalDateTime non si adatta al fuso orario dell'utente di Drupal.
Oknate

Nel mio caso l'ho appena usato prima di qualsiasi chiamata di funzione data:date_default_timezone_set(drupal_get_user_timezone());
Roger,

Grazie per questo. Mi ha davvero aiutato con drupal.stackexchange.com/q/256490/2089 .
colan,

@colan un piacere aiutarti, se pensi che la mia risposta sia utile, penso che puoi controllare anche l'altra risposta.
Adrian Cid Almaguer,

4

Di solito lo risolvo in questo modo .:

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

Questo ha funzionato per me:

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

Funziona anche per me `$ dDate = DrupalDateTime :: createFromTimestamp ($ form_state-> getValue ('service_date') -> getTimestamp (), 'UTC'); // Usa in questo modo. $ dData-> formato ('Ymd \ TH: i: s'); `
Yogesh Kushwaha il

1

Questo codice funziona per me.

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

Nessuna di queste altre risposte ha funzionato per me. Questo è quello che ho finalmente finito con:

$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

Uso questo frammento per lavorare con le date:

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

Puoi ottenere maggiori informazioni sull'oggetto Datetime qui

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.