cckのdateフィールドで入力した日付データをviewsで出力した際のフォーマットについて。

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
kenppx's picture

いつもお世話になっております。

Drupal7でサイトを構築しておりまして、問題に直面しています。
恐らく基本的な事柄だとは思いますが、ご指導頂ければ幸いです。

CCKのDateフィールドに日付を入力してviewsで出力をしようとしています。
出力フォーマットは2012年6月2日の様にしようと思います。

環境設定→地域と言語→日付と時刻 にてフォーマットを以下の様に設定しました。

Y年n月j日

このフォーマットを用いてcckのdateフィールドで入力された日付をviewsで出力をしますと
下記の様に【年月日】という文字列が日付の後に表示されてしまいます。

2012年6月2日 年月日←(これが表示されてしまいます。)

この現象はCCKのdateフィールドにて入力されたデータを出力した時にだけ起こります。
例えば、コンテンツ作成日などシステム上で作成された日付を出力する場合には
正常に下記の様に表示されます。

2012年6月2日 

上記の事から、cckの入力時のデーター形式などが適切では無いのかとも考えているのですが
現状では解決策が見つからず困っています。どなたか、解決策がありましたらご教授頂ければ
幸いです。宜しくお願い致します。

Comments

dokumori's picture

ある程度コードを読める場合、使っている field formatter のコードを見て、挙動を確認してみると良いかもしれません。 field formatter とは、cck フィールドの値をフォーマットする関数です。(確か)フックの実装のかたちで、各フィールドが備えています。

field

kenppx's picture

field formatterのコードですか…。具体的にはどのファイルを見ればよろしいでしょうか?

dokumori's picture

二重に投稿してしまったので削除しました。

sasaki2go's picture

私も同じ問題があってやむなくコアかdateモジュールの関数をハックしたことが以前ありました。
たしか、日付部分と時間部分を別々にフォーマットするように処理がされてて、時間部分のフォーマット処理で半角英文字記号であれば日付部分のフォーマット文字を正しく除去されるのだけど全角文字は除去出来ず残ってしまい表示されていました。
「2012-06-02 00:00:00」の日付データを「Y年n月j日」でフォーマットすると日付部分は「2012年6月2日」となり、時間部分は本当であれば「」空になって欲しいところが「年月日」が後ろ付加される、そんな動きをしていました。
試しに「Y年n月j日 H時i分s秒」でフォーマットすると「2012年6月2日 11時00分30秒 年月日時分秒」と全角文字がすべて後ろに付加されてしまいますね。

まさにまったく同じ症状です。

kenppx's picture

sasaki2go様のおっしゃる問題と全く同じ症状です。
全角文字だけが日付の後ろに表示されてしまうんですよ…。
打つ手がなくどうしたものかと非常に困っております。
具体的にどの様な手段で解決されたか教えて頂けないでしょうか?

dateモジュールの問題ですか…。

kenppx's picture

こちらで、同じような問題がディスカッションされているのを発見しました。
http://drupal.org/node/1538420

kenppx's picture

全角文字がなぜか$timezoneとして表示されるのが原因みたいです。対策としてdate.themeのtheme_date_single()でtimezoneを削除して非表示にしましてとりあえず対処しました。
以下、参考になった書き込みです。

Another Temporary Solution
Posted by xerxes on January 26, 2012 at 6:19pm
I also ran into this problem. After digging into the code, for some reason, those 3 extra characters are being passed to the theme function as the timezone. I don't know if its a bug or what so I just had to override theme_date_display_single(). If you don't need to display the timezone, then you should be fine by just taking timezone out.

You can find this in date/date/date.theme

function theme_date_display_single($date, $timezone = NULL) {
return ''. $date . $timezone .'';
}

ilfelice's picture

私が考えた解決方法(実際に使っています)。

① 「Y年m月d日」日付フォーマットを作成します。

② View の Date フィールドで下記のように設定します。

● 「Choose how users view dates and times:」上記の日付フォーマットに設定します。
● 「Trim this field to a maximum length」にチェックを入れて、最大長を11にする。
● 「Strip HTML tags」にチェックを入れる

これで「××××年××月××日」のみ表示され、余計な【年月日】という文字列が表示されなくなります。

参考になりました。

qchan's picture

kenppxさんの方法はtheme hookをoverrideすればハックせずに対応できそうですね。

jorgemare さんの方法もなるほど上手くいきそうです。

参考になりました。ありがとうございました。

解決策で何か進展があればわかるようにkenppxさんが見つけてくれたスレッドのリンクを貼っておきます。
Custom date formats: Write dates the Japanese way | drupal.org

ilfelice's picture

qchanさん、

実は、ご指摘のスレッドは既に拝見していました。しかし、そのスレッドに記載されている(下記の)php コードを具体的にどこに追加すれば良いかわかりませんでした。

<?php
substr_replace
($fields['field_post_date']->content, "", strrpos($fields['field_post_date']->content, " 日月年"), strlen(" 日月年"))
?>

もしわかれば、おしえていただけますか?

宜しくお願いします。

jorgemareさん、はじめまして。

qchan's picture

#編集しました。overrideする関数を変更

jorgemareさん、はじめまして。

<?php
substr_replace
($fields['field_post_date']->content, "", strrpos($fields['field_post_date']->content, " 日月年"), strlen(" 日月年"))
?>

は、どこに書くつもりだったんでしょうね。ちょっと私もわかりませんでした。

同じスレッドの theme_date_display_combination 関数を使う方法ならなんとかわかりますので、お伝えします。

  • dateモジュール内の date.themeファイルを開きます。

  • 15行目あたりからの function theme_date_display_combination をコピー
    長い関数ですが最後までコピーすること。

  • 自分のサイトで使っているThemeフォルダにtemplate.phpファイルを作って、上のFunctionをペースト

  • Function名を自分のTheme名に変更
     theme_date_display_combination >> {my_theme_name}_date_display_combination に。

  • 関数の中程にある $timezone = $dates['value']['formatted_timezone']; をコメント

  • その下に  $timezone = ''; を追記

  • ファイル保存後chache clearをする。

これで消えると思います。
あくまでtemporaryな解決策なのでDateモジュールにPatchが上がるといいんですけども。

/**
* Override theme function in date/date.theme
* Returns HTML for a date element formatted as a Start/End combination.
*
*  $entity->date_id
*    If set, this will show only an individual date on a field with
*    multiple dates. The value should be a string that contains
*    the following values, separated with periods:
*    - module name of the module adding the item
*    - node nid
*    - field name
*    - delta value of the field to be displayed
*    - other information the module's custom theme might need
*
*    Used by the calendar module and available for other uses.
*    example: 'date.217.field_date.3.test'
*
*  $entity->date_repeat_show
*    If true, tells the theme to show all the computed values of a repeating
*    date. If not true or not set, only the start date and the repeat rule
*    will be displayed.
*
*  $dates['format']
*    The format string used on these dates
*  $dates['value']['local']['object']
*    The local date object for the Start date
*  $dates['value2']['local']['object']
*    The local date object for the End date
*  $dates['value']['local']['datetime']
*    The datetime value of the Start date database (GMT) value
*  $dates['value2']['local']['datetime']
*    The datetime value of the End date database (GMT) value
*  $dates['value']['formatted']
*    Formatted Start date, i.e. 'February 15, 2007 2:00 pm';
*  $dates['value']['formatted_date']
*    Only the date part of the formatted Start date
*  $dates['value']['formatted_time']
*    Only the time part of the formatted Start date
*  $dates['value2']['formatted']
*    Formatted End date, i.e. 'February 15, 2007 6:00 pm';
*  $dates['value2']['formatted_date']
*    Only the date part of the formatted End date
*  $dates['value2']['formatted_time']
*    Only the time part of the formatted End date
*/
function bartik_date_display_combination($variables) {
  static $repeating_ids = array();

  $entity_type = $variables['entity_type'];
  $entity      = $variables['entity'];
  $field       = $variables['field'];
  $instance    = $variables['instance'];
  $langcode    = $variables['langcode'];
  $item        = $variables['item'];
  $delta       = $variables['delta'];
  $display     = $variables['display'];
  $field_name  = $field['field_name'];
  $formatter   = $display['type'];
  $options     = $display['settings'];
  $dates       = $variables['dates'];
  $attributes  = $variables['attributes'];
  $rdf_mapping = $variables['rdf_mapping'];
  $add_rdf     = $variables['add_rdf'];
  $microdata   = $variables['microdata'];
  $add_microdata = $variables['add_microdata'];
  $precision   = date_granularity_precision($field['settings']['granularity']);

  $output = '';

  // If date_id is set for this field and delta doesn't match, don't display it.
  if (!empty($entity->date_id)) {
    foreach ((array) $entity->date_id as $key => $id) {
      list($module, $nid, $field_name, $item_delta, $other) = explode('.', $id . '.');
      if ($field_name == $field['field_name'] && isset($delta) && $item_delta != $delta) {
        return $output;
      }
    }
  }

  // Check the formatter settings to see if the repeat rule should be displayed.
  // Show it only with the first multiple value date.
  list($id) = entity_extract_ids($entity_type, $entity);
  if (!in_array($id, $repeating_ids) && module_exists('date_repeat_field') && !empty($item['rrule']) && $options['show_repeat_rule'] == 'show') {
    $repeat_vars = array(
      'field' => $field,
      'item' => $item,
      'entity_type' => $entity_type,
      'entity' => $entity,
    );
    $output .= theme('date_repeat_display', $repeat_vars);
    $repeating_ids[] = $id;
  }

  // If this is a full node or a pseudo node created by grouping multiple
  // values, see exactly which values are supposed to be visible.
  if (isset($entity->$field_name)) {
    $entity = date_prepare_entity($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display);
    // Did the current value get removed by formatter settings?
    if (empty($entity->{$field_name}[$langcode][$delta])) {
      return $output;
    }
    // Adjust the $element values to match the changes.
    $element['#entity'] = $entity;
  }

  switch ($options['fromto']) {
    case 'value':
      $date1 = $dates['value']['formatted'];
      $date2 = $date1;
      break;
    case 'value2':
      $date2 = $dates['value2']['formatted'];
      $date1 = $date2;
      break;
    default:
      $date1 = $dates['value']['formatted'];
      $date2 = $dates['value2']['formatted'];
      break;
  }

  // Pull the timezone, if any, out of the formatted result and tack it back on
  // at the end, if it is in the current formatted date.
//  $timezone = $dates['value']['formatted_timezone'];
$timezone = '';
  if ($timezone) {
    $timezone = ' ' . $timezone;
  }
  $date1 = str_replace($timezone, '', $date1);
  $date2 = str_replace($timezone, '', $date2);
  $time1 = preg_replace('`^([\(\[])`', '', $dates['value']['formatted_time']);
  $time1 = preg_replace('([\)\]]$)', '', $time1);
  $time2 = preg_replace('`^([\(\[])`', '', $dates['value2']['formatted_time']);
  $time2 = preg_replace('([\)\]]$)', '', $time2);

  // A date with a granularity of 'hour' has a time string that is an integer
  // value. We can't use that to replace time strings in formatted dates.
  $has_time_string = date_has_time($field['settings']['granularity']);
  if ($precision == 'hour') {
    $has_time_string = FALSE;
  }

  // No date values, display nothing.
  if (empty($date1) && empty($date2)) {
    $output .= '';
  }
  // Start and End dates match or there is no End date, display a complete
  // single date.
  elseif ($date1 == $date2 || empty($date2)) {
    $output .= theme('date_display_single', array(
      'date' => $date1,
      'timezone' => $timezone,
      'attributes' => $attributes,
      'rdf_mapping' => $rdf_mapping,
      'add_rdf' => $add_rdf,
      'microdata' => $microdata,
      'add_microdata' => $add_microdata,
      'dates' => $dates,
    ));
  }
  // Same day, different times, don't repeat the date but show both Start and
  // End times. We can NOT do this if the replacement value is an integer
  // instead of a time string.
  elseif ($has_time_string && $dates['value']['formatted_date'] == $dates['value2']['formatted_date']) {
    // Replace the original time with the start/end time in the formatted start
    // date. Make sure that parentheses or brackets wrapping the time will be
    // retained in the final result.
    $time = theme('date_display_range', array(
      'date1' => $time1,
      'date2' => $time2,
      'timezone' => $timezone,
      'attributes' => $attributes,
      'rdf_mapping' => $rdf_mapping,
      'add_rdf' => $add_rdf,
      'dates' => $dates,
    ));
    $replaced = str_replace($time1, $time, $date1);
    $output .= theme('date_display_single', array(
      'date' => $replaced,
      'timezone' => $timezone,
      'attributes' => array(),
      'rdf_mapping' => array(),
      'add_rdf' => FALSE,
      'dates' => $dates,
    ));
  }
  // Different days, display both in their entirety.
  else {
    $output .= theme('date_display_range', array(
      'date1' => $date1,
      'date2' => $date2,
      'timezone' => $timezone,
      'attributes' => $attributes,
      'rdf_mapping' => $rdf_mapping,
      'add_rdf' => $add_rdf,
      'dates' => $dates,
    ));
  }

  return $output;
}

問題は

qchan's picture

問題は、date.themeファイルの 134行目から145行目にかけての部分

  // Pull the timezone, if any, out of the formatted result and tack it back on
  // at the end, if it is in the current formatted date.
  $timezone = $dates['value']['formatted_timezone'];
  if ($timezone) {
    $timezone = ' ' . $timezone;
  }
  $date1 = str_replace($timezone, '', $date1);
  $date2 = str_replace($timezone, '', $date2);
  $time1 = preg_replace('`^([\(\[])`', '', $dates['value']['formatted_time']);
  $time1 = preg_replace('([\)\]]$)', '', $time1);
  $time2 = preg_replace('`^([\(\[])`', '', $dates['value2']['formatted_time']);
  $time2 = preg_replace('([\)\]]$)', '', $time2);

のように思われますね。

// Pull the timezone, if any, out of the formatted result and tack it back on
// at the end, if it is in the current formatted date.

この操作をなぜしないといけないのかがわからないのですが、どなたか教えてもらえたらありがたいです。

日本語にかぎらず、 アルファベットでも Format string  に日付文字列以外の文字列を追加すると全部末尾に繰り返し付けられてしまいます。

例えばInput formatに  \Y\e\a\r-Y/\m\o\n-n/\d\a\y-j の様に書くと、 

Year-2012/mon-8/day-17 Year/mon/day

と表示されます。
( )と[ ] だけは取り外しているようですね。

英語でIssueに上げてもらえると嬉しいなぁ。

qchan

ilfelice's picture

qchan 返信が遅れてすみません。

試してませんが、ここによると…

http://drupal.org/node/1360672#comment-5783368

… date でこの問題は解決されたようです。

http://drupalcode.org/project/date.git/commit/5b99a59

もう一つ簡単な解決策

ilfelice's picture

今更感もありますが、下記のスレッドでもっと簡単な解決策みつけましたので、シェアします。

https://drupal.org/node/1143286#comment-6443784

簡単に言うと、日付型の書式に「\」下記のように追加することで、日本語の日付も正しく表示されるようになります。

BEFORE Y年n月j日
AFTER Y\年n\月j\日

ご参考までに。

これはとても簡単でした

AkshayAdhav's picture

どうもありがとうございましたjorgemare様。
本当に役に立つ解決です。