【问题标题】:Function to convert PHP date format to Javascript date format (not the date itself !)将 PHP 日期格式转换为 Javascript 日期格式的函数(不是日期本身!)
【发布时间】:2019-12-08 07:52:26
【问题描述】:

我正在寻找将 PHP 日期格式(即 Y-m-d H:i:s)转换为 javascript 日期格式(分别为 YYYY-mm-dd HH:mm:ss)的简单方法。

我不想转换日期(已经有这个问题的答案),我正在寻找工具/函数来转换格式代码(我不想还知道,因为它是由用户在应用程序中定义的)。

用户可以通过 PHP date() 定义的不同方式定义它,即“Y/m/d H:i”或“Y-d-m H-i”,在 javascript 中显示日期时我需要使用相同的格式。

你知道任何现成的转换函数吗?

<?php
$timeformat_php = "H:i:s"; //just defined by the user
$time_universal = date( $timeformat_php, strtotime( $time_php ) );
echo date($timeformat_php, $time_universal); //print as defined by user
?>

<script>
var timeformatPhp = '<?php echo $timeformat_php ?>';
var timeformatJavascript = functionThatIamLookingFor (timeformatPhp);
alert(moment($time_universal).format(timeformatJavascript); //printed again the way user defined
</script>

任何帮助将不胜感激。谢谢。

【问题讨论】:

  • 我担心你的问题跑题了,见help center。看看moment-strftime,即使我不确定它是否对你有帮助。
  • 您需要的是一个 ECMAScript 格式化程序,它使用与 PHP 相同的标记。它们可能存在,但这些问题不在此处讨论。
  • 例如您可以查看 Fecha.js 的源代码,从第 66 行开始,您可以看到解析和格式化标记。因此,您只需要将格式化标记从 PHP 映射到 Fecha.js,然后使用 Fecha.js 格式化程序。同样的方法也可以用于其他库。我建议使用 Fech.js,因为它不到 300 行代码,并且在解析和格式化方面做得很好。
  • 我的反击是:根本不要让用户编写自己的日期格式字符串,因为当用户尝试使用一些深奥的格式说明符时,尝试自动转换将是一场噩梦不翻译。提供他们可以选择的选项,如果他们不喜欢,他们可以提出建议和/或敲沙子。
  • 萨米奇-谢谢。非常有用的计数器。我会认真考虑的!

标签: javascript php sql date momentjs


【解决方案1】:

如果您要求的是使用 PHP 格式化标记来格式化 ECMAScript Date 对象,那么以下内容可能会有所帮助。它支持除时区名称之外的所有标记。我认为您不能仅在浏览器中使用 javascript 可靠地做到这一点,尽管 node.js 之类的东西可能能够做到。

还有一些功能可以使用,例如是否遵守夏令时以及生成 RFC 2822 格式字符串,但我认为它们很容易添加。它支持带引号的字符,因此您可以构建如下字符串:

P.format(date, 'jS \\o\\f F, Y') // 1st of August, 2019

任何与标记不匹配的字符都会被复制到输出字符串中(例如上面的空格和逗号)。

// Parser and formatter using PHP tokens
let P = function(global) {

  let P = {lang: 'en-GB'};

  // Format tokens and functions
  let tokens = {
  
    // DAY
    // day of month, pad to 2 digits
    d: d => pad(d.getDate()),
    // Day name, first 3 letters
    D: d => getDayName(d).substr(0,3),
    // day of month, no padding
    j: d => d.getDate(),
    // Full day name
    l: d => getDayName(d),
    // ISO weekday number (1 = Monday ... 7 = Sunday)
    N: d => d.getDay() || 7,
    // Ordinal suffix for day of the month
    S: d => getOrdinal(d.getDate()),
    // Weekday number (0 = Sunday, 6 = Saturday)
    w: d => d.getDay(),
    // Day of year, 1 Jan is 0
    z: d => {
      let Y = d.getFullYear(),
          M = d.getMonth(),
          D = d.getDate();
      return Math.floor((Date.UTC(Y, M, D) - Date.UTC(Y, 0, 1)) / 8.64e7) ;
    },
    // ISO week number of year
    W: d => getWeekNumber(d)[1],
    // Full month name
    F: d => getMonthName(d),
    // Month number, padded
    m: d => pad(d.getMonth() + 1),
    // 3 letter month name
    M: d => getMonthName(d).substr(0, 3),
    // Month number, no pading
    n: d => d.getMonth() + 1,
    // Days in month
    t: d => new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate(),
    // Return 1 if d is a leap year, otherwise 0
    L: d => new Date(d.getFullYear(), 1, 29).getDate() == 29? 1 : 0,
    // ISO week numbering year
    o: d => getWeekNumber(d)[0],
    // 4 digit year
    Y: d => {
      let year = d.getFullYear();
      if (year < 0) {
        year = '-' + ('000' + Math.abs(year)).slice(-4);
      }
      return year;
    },
    // 2 digit year
    y: d => {
      let year = d.getFullYear();
      if (year >= 0) {
        return ('0' + year).slice(-2);
      } else {
        year = Math.abs(year);
        return - + ('0' + year).slice(-2);
      }
    },
    // Lowercase am or pm
    a: d => d.getHours() < 12? 'am' : 'pm',
    // Uppercase AM or PM
    A: d => d.getHours() < 12? 'AM' : 'PM',
    // Swatch internet time
    B: d => (((+d + 3.6e6) % 8.64e7) / 8.64e4).toFixed(0),
    // 12 hour hour no padding
    g: d => (d.getHours() % 12) || 12,
    // 24 hour hour no padding
    G: d => d.getHours(),
    // 12 hour hour padded
    h: d => pad((d.getHours() % 12) || 12),
    // 24 hour hour padded
    H: d => pad(d.getHours()),
    // Minutes padded
    i: d => pad(d.getMinutes()),
    // Seconds padded
    s: d => pad(d.getSeconds()),
    // Microseconds padded - always returns 000000
    u: d => '000000',
    // Milliseconds
    v: d => padd(d.getMilliseconds()),
    // Timezone identifier: UTC, GMT or IANA Tz database identifier - Not supported
    e: d => void 0,
    // If in daylight saving: 1 yes, 0 no
    I: d => d.getTimezoneOffset() == getOffsets(d)[0]? 0 : 1,
    // Difference to GMT in hours, e.g. +0200
    O: d => minsToHours(-d.getTimezoneOffset(), false),
    // Difference to GMT in hours with colon, e.g. +02:00
    P: d => minsToHours(-d.getTimezoneOffset(), true),
    // Timezone abbreviation, e.g. AEST. Dodgy but may work…
    T: d => d.toLocaleString('en',{year:'numeric',timeZoneName:'long'}).replace(/[^A-Z]/g, ''),
    // Timezone offset in seconds, +ve east
    Z: d => d.getTimezoneOffset() * -60,
    
    // ISO 8601 format - UTC
    // c: d => d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) +
    //        'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) +
    //        '+00:00',
    
    // ISO 8601 format - local
    c: d => P.format(d, 'Y-m-d\\TH:i:sP'),
    // RFC 2822 formatted date, local timezone
    r: d => P.format(d, 'D, d M Y H:i:s O'),
    // Seconds since UNIX epoch (same as ECMAScript epoch)
    U: d => d.getTime() / 1000 | 0
  };
  
  // Helpers
  // Return day name for date
  let getDayName = d => d.toLocaleString(P.lang, {weekday:'long'});
  // Return month name for date
  let getMonthName = d => d.toLocaleString(P.lang, {month:'long'});
  // Return [std offest, DST offset]. If no DST, same offset for both
  let getOffsets = d => {
    let y = d.getFullYear();
    let offsets = [0, 2, 5, 9].map(m => new Date(y, m).getTimezoneOffset());
    return [Math.max(...offsets), Math.min(...offsets)];
  }  
  // Return ordinal for positive integer
  let getOrdinal = n => {
    n = n % 100;
    let ords = ['th','st','nd','rd'];
    return (n < 10 || n > 13) ? ords[n%10] || 'th' : 'th';
  };
  // Return ISO week number and year
  let getWeekNumber = d => {
    let e = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
    e.setUTCDate(e.getUTCDate() + 4 - (e.getUTCDay()||7));
    var yearStart = new Date(Date.UTC(e.getUTCFullYear(),0,1));
    var weekNo = Math.ceil(( ( (e - yearStart) / 86400000) + 1)/7);
    return [e.getUTCFullYear(), weekNo];
  };
  // Return true if o is a Date, otherwise false
  let isDate = o => Object.prototype.toString.call(o) == '[object Date]';
  // Convert numeric minutes to +/-HHMM or +/-HH:MM
  let minsToHours = (mins, colon) => {
    let sign = mins < 0? '-' : '+';
    mins = Math.abs(mins);
    let H = pad(mins / 60 | 0);
    let M = pad(mins % 60);
    return sign + H + (colon? ':' : '') + M;
  };
  // Pad single digits with a leading zero
  let pad = n => (n < 10? '0' : '') + n;
  // Pad single digits with two leading zeros, double digits with one leading zero
  let padd = n => (n < 10? '00' : n < 100? '0' : '') + n;
  // To be completed...
  let parse = s => 'not complete';

  P.parse = parse;
  
  // Format date using token string s
  function format(date, s) {
    // Minimal input validation
    if (!isDate(date) || typeof s != 'string') {
      return; // undefined
    }

    return s.split('').reduce((acc, c, i, chars) => {
      // Add quoted characters to output
      if (c == '\\') {
        acc += chars.splice(i+1, 1);
      // If character matches a token, use it
      } else if (c in tokens) {
        acc += tokens[c](date);
      // Otherwise, just add character to output
      } else {
        acc += c;
      }
      return acc;
    }, '');
  }
  P.format = format;
  
  return P;
}(this);


// Examples
console.log('Today is ' + P.format(new Date(), 'l, jS \\o\\f F, Y'));
let startPWars = new Date(-431,3,25);
let endPWars   = new Date(-404,0);
console.log('The Peloponnesian Wars started on ' + 
  P.format(startPWars, 'd F, Y') +
  ' and ended in ' +
  P.format(endPWars, 'Y'));

function showDate() {
  let format = document.getElementById('i0').value;
  document.getElementById('sp0').textContent = P.format(new Date(), format) || 'invalid tokens';
}
<input id="i0" placeholder="PHP format, e.g. d-M-Y">
<button onclick="showDate()">Show formatted date</button>
<br>
<span id="sp0"></span>

【讨论】:

  • 谢谢,我会调查,但看起来像我正在寻找的东西。
  • 很棒的功能,@RobG,谢谢!但是对于“y”(两位数的年份符号),它在 >1999 年将无法正常工作,因为 JS 将返回三位数字(例如,119 表示 2019 年)。可能new String(a.getFullYear()).substr(-2) 会更好。
  • @WASD42——事实上,在 20 世纪以外的任何一年都失败了。我已经应用了您建议的编辑,但这不适用于负数年。当我有时间的时候,我会多做一点。 :-)
  • @RobG “负数”是指公元前几年吗?它应该可以正常工作,这取决于应该显示的内容,当然,作为两位数的年份。比如说,var d = new Date('1900-01-01'); d.setYear(-710); console.log(('0' + d.getFullYear()).substr(-2)); 会将“10”记录到控制台。
  • @WASD42 — 它现在返回前导 - 表示 1 之前的年份(负数、BC、BCE 等),用于两位数和四位数年份。 PHP 是做什么的? PS不确定公历的历史价值可以追溯到那么远,也许几年是可以的,但几天和几个月是没有实际意义的。
猜你喜欢
  • 2012-06-05
  • 2016-12-02
  • 1970-01-01
  • 2017-10-12
  • 1970-01-01
  • 2018-05-05
  • 1970-01-01
  • 1970-01-01
  • 2018-02-12
相关资源
最近更新 更多