1

私は、次の難問で数日間頭を悩ませてきました。

私は基本的に次の複雑なmySQLテーブルを持っています:

    | ID |   TITLE      |    DESCRIPTION    | EVENT |      DATE               |
    |----|--------------|-------------------|-------|-------------------------|
    |  1 | Big painting | 3-day work        |  No   | 03/10/2013              |
    |  2 | Meeting      | With reps.        |  Yes  | 02/15/2013 09:00 -05:00 |
    |  3 | Presentation | 5 paintings       |  Yes  | 08/02/2013 22:00 +02:00 |
    |  4 | Round paint. | One week          |  No   | 04/05/2013              |
    |  5 | Conference   | On Picasso        |  Yes  | 04/22/2013 18:00 -05:00 |

(編集: おそらく、DATE 列が [データにタイムゾーンを含める必要があるため] DATE または DATETIME として設定されているのではなく、VARCHAR として設定されていることを明確にする必要があるため、最初から組織が複雑になっています。)

ご覧のとおり、これは、たとえばペインター向けのすべての「最新情報」項目を含むテーブルです。このペインターの Web サイトでは、PHP が値を呼び出して、"What's New" ニュース ティッカーとして表示するという考え方です。

すべての基本はそこにありますが、私は思わぬ障害にぶつかっています。

最初は、SELECT 段階でデータをフィルタリングして並べ替えたいと思っていましたが、それがうまくできませんでした。ご覧のとおり、イベントと非イベント アイテムのボットには日付がありますが、非イベント アイテムには、全体的なデータを整理する方法として日付が含まれているだけです。特定の日付と時刻は、イベントの場合にのみ重要です。これにより、ユーザーはこれらのイベントがいつ発生したかを知ることができます。したがって、基本的な考え方は、テーブルから特定の数の LATEST 項目を選択することです。したがって、すべての項目がテーブルから読み取られ、DATE の順に配置されてから、たとえば 20 個の項目が取り出されます。

前述したように、最初は SELECT 段階でこれを行うことを考えていましたが、複雑すぎる可能性があると思います。そのため、すべてのアイテムを抽出し、フィルタリングするためにそれらの後に PHP コードを設定しました。

そのため、日付を注文しようとすると問題が発生します。注文プロセスのために日付をタイムスタンプに変換してから、表示のために日付に戻そうとしています。ただし、日付-タイムスタンプまたはタイムスタンプ-日付 (またはその両方) の変換が機能しません。私はいつも、最初の日付とは異なる日付になってしまいます。

ご覧のとおり、タイムゾーンが原因で全体がより複雑になっています。タイムゾーンは非常に重要です。ユーザーは、これらのことがどこで発生しているか、または発生している場所に応じて何時に発生しているかを知ることができなければならないためです。

私は単純に前後に変換しようとしました:

    $timestamped = strtotime($date);
    $datetimed = date('m/d/Y h:i P',$timestamped);

うまくいかないので、テーブルで使用している日付形式に関係があると思いました。

それで、私はこれを試しました:

    $var = DateTime::createFromFormat('m/d/Y H:i P',$date)->getTimestamp();

無駄に、まだ...

おそらく、プロセスの開始時、つまりデータ項目を挿入するときにタイムスタンプを設定する必要があると考えています。しかし、ここでも「人間の」日付をタイムスタンプに変換する必要があり、これを正しく管理できなければ、何も適切に機能しません。

この質問が複雑であることは理解していますが、おそらく私の説明が最も明確ではないでしょう! おそらく、出力例が役立つかもしれません。私が達成しようとしているのは、起こっていることのリストを含む「What's New」ニュース ティッカーです。そのうちのいくつかは、目に見える日付のない単なる情報 (ステータスの更新など) です (ここでの日付は内部組織のためだけのものです)。 ; ここで EVENT 列の出番です。日付を表示する必要があるアイテムと、日付を表示してはならないアイテム)、その他、ユーザーが招待される実際のイベント、およびユーザーの日付を表示するアイテムをフィルター処理します。まだ過去ではないイベントに「UPCOMING」タグを表示するために、日時が過去か未来かを計算するコードもあります。ただし、日付の処理と注文に問題があります。

これは、この例が最終的に多かれ少なかれ次のようになるはずです。

完成品例

どんな助けでも大歓迎です!(また、このデータ検索/整理プロセスを処理する最も実用的で最もクリーン/エレガント/プロの方法であると思われるものについてのフィードバック...データ入力の場合、mySQL SELECT ステージの場合、後でなど. )

PSおそらく、同じテーブルに他のデータを処理することを追加するかもしれません。この特定の "What's New" データは、特定の WHATSNEW 列を検索する SELECT 関数によって選択され、この特定の "What's New" ニュース ティッカーに対して取得されるすべての行で TRUE の値を持ちます。


解決策(回答ではありません)

質問は、いわば時間とタイムゾーンを 1 つの文字列として整理することに関するものだったので、これら 2 つの優れた回答のいずれかを、その特定の問題について正しいとマークできるかどうかはわかりません。私がやったことは、タイムゾーンを取り除いて別の列に入れることでした。次に、日付列を日時としてフォーマットしました。mySQL Select が私に代わって注文を処理できるので、私はそれを解決しました。さて、タイムゾーンについてですが、私は少しごまかしてしまいました。私たちの「アーティスト」が、2 つの異なるタイムゾーンで同時に 2 つのイベントに参加することはあり得ないと考えました。それぞれのタイムゾーンが最初に来る本当の違いを生むほど接近しているイベント。したがって、私は物事自体を日付順に並べてから、スニペットを作成してタイムゾーンを処理し、それらを「GMT + 1」、「GMT-5」表示に変換して、ユーザーがその場所がどこにあるかを知るようにしました現地時間。結局使ってしまったDateTime::createFromFormat()->getOffset()、2番目の回答者が推奨しているのを見て、正しい軌道に乗っていると言っていたので、そこに保管しておいてよかったです.これをさらに明確にするために、ウェブマスターができる場所列を追加しました.都市を指定するには、「パリ」、「ロンドン」などと言ってください。したがって、ユーザーは、私の例に示されているものと非常によく似たものを持つことになります... (Paris, GMT+1)

とにかく、まったく同じ問題を抱えていて、まったく同じことを考えてしまい、この方法がより実用的であるという人のために、ここに私が最終的に得たコードの核心があります. 残りは「埋める」だけです。楽しみ!そして、この問題の解決策を見つけるために時間を割いてくれた親切な二人に感謝します! (余計なことがあるかもしれ}ません…申し訳ありません。SOに貼り付けるときの再フォーマットは本当に面倒です!コードを2回修正しましたが、問題は見つかりませんでした。)

if(isset($item) && $item['event'] == '1') {
  $event = $item['event'];
  $date  = $item['date'];

  $date_array = date_parse($date);

  $minute = $date_array['minute'];
  if($minute<10) {
    $minute = '0'.$minute;
  }

  $timezone = $item['timezone'];
  if($timezone!=='') {
    $timezone = DateTime::createFromFormat('P',$timezone)->getOffset();
    $timezone = $timezone/-3600;
    if($timezone<0) {
      $timezone = $timezone;
    } else
    if($timezone==0) {
      $timezone = '-0';
    } else {
      $timezone = '+'.$timezone;
    }
    $timezone = 'Etc/GMT'.$timezone;

    $timezone_real = $item['timezone'];
    $timezone_real = DateTime::createFromFormat('P',$timezone)->getOffset();
    $timezone_real = $timezone_real/-3600;
    if($timezone_real<0) {
      $timezone_real = str_replace('-','+',$timezone_real);//.':00';
    } else
    if($timezone_real==0) {
      $timezone_real = '+0';//:00';
    } else {
      $timezone_real = '-'.$timezone_real;//.':00';
    }
    $timezone_real = 'GMT'.$timezone_real;

    date_default_timezone_set($timezone);
  }

$today = date('n/j/Y G:i', time());
$today = strtotime($today);
$event_date = $date_array['month'].'/'.$date_array['day'].'/'.$date_array['year'].' '.$date_array['hour'].':'.$minute;
$event_date_unformatted = strtotime($event_date);

if($date_array['hour'] == '0') {
  $hour_convert = '12';
  $hour_suffix = 'a.m.';
} else if($date_array['hour']<12) {
  $hour_convert = $date_array['hour'];
  $hour_suffix = 'a.m.';
} else if($date_array['hour'] == '12') {
  $hour_convert = $date_array['hour'];
  $hour_suffix = 'p.m.';
} else {
  $hour_convert = $date_array['hour']-12;
  $hour_suffix = 'p.m.';
}

$date_convert = array('1'  => 'January', '2'  => 'February', '3'  => 'March', '4'  => 'April', '5'  => 'May', '6'  => 'June', '7'  => 'July', '8'  => 'August', '9'  => 'September', '10' => 'October',  '11' => 'November', '12' => 'December');

$event_date = $date_convert[$date_array['month']].' '.$date_array['day'].', '.$date_array['year'].', '.$hour_convert.':'.$minute.' '.$hour_suffix;

if(($event_date_unformatted-$today)>0) {
  echo '<h5>UPCOMING:</h5>';
  echo '<h6>'.$item['location'].', '.$event_date.' <sup>('.$timezone_real.')</sup></h6>';
}
}
4

2 に答える 2

2

あなたはそれDateTime::createFromFormatがうまくいかないと言いますが、エラーメッセージが何であるかを教えてはいけません. あなたのフォーマット文字列があなたが渡しているフォーマットを表していないからだと思います。受け入れ可能な形式については、マニュアル ページを参照してください。

そうは言っても、あなたは正しい軌道に乗っていたと思いますDateTime::createFromFormat。それが私がとるアプローチです。私よりも強力な SQL foo を持っている人なら、クエリを使ってこれを行う方法を思いつくかもしれませんが、日付でソートされたイベントの配列を取得するための私の純粋な PHP アプローチは次のとおりです。

//first we connect to our database
$dsn = 'mysql:dbname=stackoverflow;host=127.0.0.1';
$user = '********';
$password = '*********';

try {
    $dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
}

//then we get our list of events from the table
$sql = "select * from datetable";

$select = $dbh->prepare($sql);
$select->execute();

//We now have an associative array of events, but in the wrong order.
$results = $select->fetchAll(PDO::FETCH_ASSOC);

$events = array();

//we want to sort on date, so lets get the dates into a format we can sort on
foreach($results as $result){
    $event = $result;
    $date = explode(' ', $result['date']);
    if(isset($date[1])){
        $event['date'] = \DateTime::createFromFormat('m/d/Y H:i', $date[0] . ' ' . $date[1]);
        $event['tz'] = $date[2];
    } else {
        $event['date'] = \DateTime::createFromFormat('m/d/Y', $date[0]);
    }
    $events[] = $event;
}

//our sorting function
$byDate = function(array $eventA, array $eventB){
    return $eventB['date'] > $eventA['date'] ? -1 : 1;
};

//sort the array
usort($events, $byDate);

//we now have our array sorted correctly
var_dump($events);

結果:-

array (size=5)
  0 => 
    array (size=6)
      'id' => string '2' (length=1)
      'title' => string 'Meeting' (length=7)
      'description' => string 'With reps.' (length=10)
      'event' => string 'Yes' (length=3)
      'date' => 
        object(DateTime)[4]
          public 'date' => string '2013-02-15 09:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/London' (length=13)
      'tz' => string '-05:00' (length=6)
  1 => 
    array (size=5)
      'id' => string '1' (length=1)
      'title' => string 'Big painting' (length=12)
      'description' => string '3-day work' (length=10)
      'event' => string 'No' (length=2)
      'date' => 
        object(DateTime)[3]
          public 'date' => string '2013-03-10 23:18:05' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/London' (length=13)
  2 => 
    array (size=5)
      'id' => string '4' (length=1)
      'title' => string 'Round paint.' (length=12)
      'description' => string 'One week' (length=8)
      'event' => string 'No' (length=2)
      'date' => 
        object(DateTime)[6]
          public 'date' => string '2013-04-05 23:18:05' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/London' (length=13)
  3 => 
    array (size=6)
      'id' => string '5' (length=1)
      'title' => string 'Conference' (length=10)
      'description' => string 'On Picasso' (length=10)
      'event' => string 'Yes' (length=3)
      'date' => 
        object(DateTime)[7]
          public 'date' => string '2013-04-22 18:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/London' (length=13)
      'tz' => string '-05:00' (length=6)
  4 => 
    array (size=6)
      'id' => string '3' (length=1)
      'title' => string 'Presentation' (length=12)
      'description' => string '5 paintings' (length=11)
      'event' => string 'Yes' (length=3)
      'date' => 
        object(DateTime)[5]
          public 'date' => string '2013-08-02 22:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/London' (length=13)
      'tz' => string '+02:00' (length=6)

未解決の主な問題はタイムゾーンです。データベースには、タイムゾーンではなくオフセットが保存されます。これについては SO に関するいくつかの質問があります (例: this one )。そのため、ここではそれらの取り組みについては詳しく説明しませんが、方法が見つかった場合は、配列でオフセットを利用できます。

あなたのコメントで、タイムゾーンの列を追加することを検討していることに気付きました。これは良い考えです。ただし、このリストから TZ 文字列として保存することをお勧めします。その後、 DateTimeZoneのコンストラクターに直接渡して、夏時間の許容などの利点を得ることができます。

于 2013-05-25T22:32:56.250 に答える
1

SQLクエリは

   $data= mysql_query( "SELECT * FROM (table name) ORDER BY date ASC")

最新のコメントに基づいてアルゴリズムを追加しています。

まず、DATE列のデータ型は統一されている必要があります。日時またはタイムスタンプ形式の場合、データを正しく並べ替える必要があります。

このリンクは、日付と時刻関数の包括的なリストを提供します。問題を解決するためのより良い感覚を得るために読む価値があります。

http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html

日付の正しいフォーマットに対処するこのリンクを参照してください-(ただし、よりクリーンなテーブルの場合、テーブルに受け入れるフォーマットは1つだけにすることをお勧めします):

日付の降順 - 月、日、年

オンラインで使用する場合: タイムゾーンを「標準化」する必要があると思います。タイムスタンプは、すべてのイベントに対して同じタイムゾーン内で作成できます。ユーザーは、選択したタイムゾーンに従ってこれらの時間を表示できます。したがって、すべての時間はユーザーごとに調整されます。

このリンクでは、タイムゾーンのセッション変数について説明しています: http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html

接続ごとのタイム ゾーン。接続する各クライアントには、セッションの time_zone 変数によって指定される独自のタイム ゾーン設定があります。最初に、セッション変数はグローバルな time_zone 変数から値を取得しますが、クライアントは次のステートメントで独自のタイム ゾーンを変更できます。

mysql> SET time_zone = タイムゾーン;

ただし、ローカルで使用する場合、個人が最新情報に参加する目的で更新のチラシを受け取る可能性がある場合は、その地域のタイムゾーンを、言及された地域とともに表示する必要があります。たとえば GMT +2.00 を追加しても、多くのユーザーは自分のタイムゾーンを参照して時刻を示すことはできず、通常は自分で変換する必要があります。これにより、ユーザーのフラストレーションがさらに高まります。ユーザーのために変換するか、時差について何らかの説明を提供することは、努力する価値があります。これにより、ユーザーは、自分のタイムゾーンに関してこのイベントが「いつ」発生しているかを明確に理解できます。

タイムゾーンに対処するには、次のリンクにアクセスする価値があります: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_convert-tz

CONVERT_TZ() は、日時値 dt を from_tz で指定されたタイム ゾーンから to_tz で指定されたタイム ゾーンに変換し、結果の値を返します。タイム ゾーンは、セクション10.6「MySQL サーバーのタイム ゾーン サポート」で説明されているように指定されます。引数が無効な場合、この関数は NULL を返します。

from_tz から UTC への変換時に、値が TIMESTAMP 型のサポート範囲外の場合、変換は行われません。TIMESTAMP の範囲は、セクション11.1.2「日付と時刻型の概要」で説明されています。

mysql> SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET'); -> '2004-01-01 13:00:00' mysql> SELECT CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00'); -> '2004-01-01 22:00:00' 注意 'MET' や 'Europe/Moscow' などの名前付きタイム ゾーンを使用するには、タイム ゾーン テーブルを適切に設定する必要があります。手順については、セクション10.6「MySQL サーバーのタイム ゾーン サポート」を参照してください。

列を追加すると、問題が解決すると思います。

で考える

  1. データ型の確認
  2. タイムゾーンの標準化
  3. タイムゾーンを表示する別の列を追加する

テーブルの注文に問題はありません。

これが役立つことを願っています。私にお知らせください。

于 2013-05-25T19:12:44.127 に答える