Moment: 機能のリクエスト:より正確な.humanize

作成日 2012年06月24日  ·  112コメント  ·  ソース: moment/moment

.humanizeは、秒に関しては実際には正確ではありません。

moment.duration(40, 's').humanize() === "a few seconds" // expected "40 seconds"
moment.duration(45, 's').humanize() === "a minute" // expected "45 seconds"

このレベルの精度はあまり必要ないことは理解していますが、人間が読める形式で正確な値が必要な場合もあります。

この機能をサポートするために、APIに変更を加えることをお勧めします(実際に表示されているものとは下位互換性があるようです)。

moment.duration(40, 's').humanize() === "a few seconds"
moment.duration(40, 's').humanize(true) === "in a few seconds"

moment.duration(40, 's').humanize({precise:true}) === "40 seconds"

moment.duration(40, 's').humanize({suffix:true, precise:true}) === "in 40 seconds"
moment.duration(40, 's').humanize({precise:false, suffix:true}) === "in a few seconds"

どう思いますか ?

Enhancement New Feature

最も参考になるコメント

moment.duration(183, "minutes").humanize() // 3 hours

3時間3秒のような正確な出力があると便利です。

全てのコメント112件

@FGRibreau 、この問題は#232で発生し、そこのOPはコアに追加しなくても問題ないようでした。

より正確な相対時間を知りたい場合は、 precise-englishなどの言語定義を記述できます。 1.7.0でリリースされる新しいインスタンス言語機能により、非常に便利になる可能性があります。 現在、どの言語定義も英語から指定されていないすべての値を継承するため、relativeTimeディクショナリを変更する必要があります。 残念ながら、継承は辞書内で継承されないため、辞書全体を指定する必要があります。

注意: #232で説明されている方法は、#332での変更により、1.7.0では機能しなくなります。

moment.lang('precise-en', {
    relativeTime : {
        future : "in %s",
        past : "%s ago",
        s : "%d seconds", //see https://github.com/timrwood/moment/pull/232#issuecomment-4699806
        m : "a minute",
        mm : "%d minutes",
        h : "an hour",
        hh : "%d hours",
        d : "a day",
        dd : "%d days",
        M : "a month",
        MM : "%d months",
        y : "a year",
        yy : "%d years"
    }
});

// one way
moment.lang('precise-en');
moment.duration({s: 40}).humanize();

// other way
moment.duration({s: 40}).lang('precise-en').humanize();

これを簡単にする1つのことは、継承が機能することです。これにより、 relativeTimeオブジェクト内で1つの値を指定するだけで済みます。 @timrwood 、_smarter_継承が必要だと思いますか?

よりスマートな継承を追加する場合は、CLDRのようなことを実行して、各サブ言語にマスター言語から継承させたいと思います。 したがって、 fr_CAfrから継承し、 en_GBenから継承します。

ただし、「relativeTime.s」のみを変更するために、深い拡張を行う必要はないと思います。

@FGRibreauは、 precise-en言語定義に沿って何かをしましたか?

これを@rockymezaのソリューションとして閉じることが、これを処理するための推奨される方法です。

これは数秒以上に適用されます。 同じことが時間、年などにも当てはまります...

ええ、そして好ましい解決策は英語を話す聴覚にのみ好まれます。 他の言語では、名詞の語尾変化(曲用)に悩まされる必要があります。

この問題に重みを付けます。 カウントダウンを考案するときは、精度が必要です。

ですから、過去を見ると「10時間前」でもいいのですが、イベントを待ち望んでいるのなら「10時間3分8秒で」したいです。

それを得るために私がカスタム言語を書かなければならないことを私に言わないでください?

moment.duration(183, "minutes").humanize() // 3 hours

3時間3秒のような正確な出力があると便利です。

この機能も欲しいです。

正確な人間化バージョンも必要です!

また、Momentのヒューマナイズが(オプションで)より正確であるとよいと思いますが、今ここに解決策を探しに来た人にとっては、 HumanizeDuration.jsが非常にうまく機能することがわかりました。

var
  moment = require('moment'),
  humanizeDuration = require('humanize-duration');

console.log(humanizeDuration(moment.duration('PT1H15M').asMilliseconds())); // '1 hour, 15 minutes'

// whereas:

console.log(moment.duration('PT1H15M').humanize()); // 'an hour'

「正確なヒューマナイズ」オプションを見たいのですが、瞬間に追加のライブラリを使用する必要があるのは少し不格好です。

正確に人間化するための+1!

正確なヒト化期間を取得するオプションがないことに本当に失望しました。 :|

ドキュメントで参照されているPreciseRangeと呼ばれるプラグインがあります。 誰かがそれを試しましたか?

Precise Rangeは技術的には機能しますが、モーメントオブジェクトではなく文字列を返すように見えるため、どの日付部分が好きかを具体的に特定することはできません。

言語(imo)も少しずれており、1つの結果は-'1時間19分数秒'でした。 1時間19分数秒くらい見たいです。 単語と数字を混ぜることは、常に文法的に少しノーノーでした(私が知る限り)。

正確な瞬間を人間化するための+1

@Envek Precise Rangeは良さそうですが、i18n/l10nはサポートしていません...

少なくとも2つか3つのプロジェクトでこれが必要だったので、moment.jsによる公式サポートがあればいいのですが。

@topaxi +1

+1

@doingweb HumanizeDuration.jsモジュールがかなりうまく機能することを確認しました!

正確な瞬間を人間化するための+1

より正確な瞬間を人間化するための+1

+1

+1

+1

+1

+1

+1

+1

なぜこれがいつも閉まっているのですか? これは、moment.jsに実装する必要がある最も明白な機能です。 まだ入っていないことに実はショックを受けました。 Humanizeは、それがないフォーラムの投稿のように、漠然とした時間表示以外ではまったく役に立たない。

+1

+1

+1

-1。 私はそれが今どのように機能するかを人間化するのが好きです。 それは持続時間の「人間に優しい」バージョンを与えることになっています。

「ねえフランク、いつそのメールを送ったの?」
"約一分前。"

vs

「ねえフランク、いつそのメールを送ったの?」
「43秒前」

どちらがより「人間的」に見えますか?

より正確なバージョンが現在のものを置き換えることは想定されていませんでした。 新機能のリクエストです。

+ 1、 @ mattgrande現在の内容は過去の期間を説明するのに最適ですが、たとえば「1時間30分」などの予定の長さを説明するのには適していません。

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

私からのこれのための+1。 新しい言語定義を作成したり、既存の言語定義を変更したりしても、実際には機能しません。 現在Momentでサポートされている言語は108あるようです。そのため、108の定義を手動で変更する必要があります(そして、すべてが文法的に正しいことを願っています)。または、英語を話さないユーザーのことを忘れてしまいますか? それらのどちらも良い解決策のようには聞こえません...

私はこれを使用しています:

`` `` javascript
var humanizeDuration = function(eventDuration){
eventMDuration = moment.duration(eventDuration、'seconds');
eventDurationString = ""
if(eventMDuration.days()> 0)
eventDurationString + = "" + moment.duration(eventMDuration.days()、'days')。humanize()
if(eventMDuration.hours()> 0)
eventDurationString + = "" + moment.duration(eventMDuration.hours()、'hours')。humanize()
if(eventMDuration.minutes()> 0)
eventDurationString + = "" + moment.duration(eventMDuration.minutes()、'minutes')。humanize()

eventDurationString.trim()を返します
}
`` `` ``

+1

この機能がないと+1、タイムトラッキングはできません。

なぜ問題はクローズされますか?

+1

+1

+1

オプションでより正確なオプションを追加する機能は、それでも「人間」オプションは非常に価値があります。

+1

+1

+1

+1

+1。 期間を正確に、しかし人間の形式で表示する必要がある会計アプリケーションに取り組んでいます。 「1年、2か月、3日」は「398日」よりも優れていますが、「1年」は実際には受け入れられません。

現在の実装は、基本的に役に立たないほど人間的です。

+1

duration.humanizeには、単位が1分、1時間などと見なされるタイミングを定義するしきい値があります。 たとえば、デフォルトでは、45秒を超えると1分、22時間を超えると1日と見なされます。 これらのカットオフを変更するには、 moment.relativeTimeThreshold(unit, limit)を使用します。ここで、単位はsssmhdのいずれかです。 、 M

https://momentjs.com/docs/#/customization/relative -time-threshold /

+1

+1

+1、この号を開くことを再検討してください😍

+1

+1

+1

+1

+1

+1

私は次のようなものを使用します:

function stringifyDuration(duration) {
    // Return a human readable string representing the given moment duration

    // Split the duration into parts, and drop the most significant parts with a value of 0
    const durationParts = _.dropWhile([
        { value: duration.years(), unit: 'year' },
        { value: duration.months(), unit: 'month' },
        { value: duration.days(), unit: 'day' },
        { value: duration.hours(), unit: 'hour' },
        { value: duration.minutes(), unit: 'minute' },
        { value: duration.seconds(), unit: 'second' },
        { value: duration.milliseconds(), unit: 'millisecond' },
    ], (part) => part.value === 0);

    // Display up to two of the most significant remaining parts
    return _.take(durationParts, 2).map((part) => (
        `${part.value} ${pluralize(part.unit, part.value)}`
    )).join(', ');
}
> stringifyDuration(moment.duration(26, 'hours'))
"1 day, 2 hours"

lodash複数形を使用します。

@timrwoodこれを実装するためのケース:

  1. @rockymezahttps://github.com/moment/moment/issues/348#issuecomment-6535794ソリューションは、あなたとあなたの寄稿者はすでに多くの言語に翻訳するという驚くべき仕事をしています
  2. @mattgrande https://github.com/moment/moment/issues/348#issuecomment -237830415すでに十分に人間的であるという議論は、その種がうまく機能する部分を呼び出しているだけです。 この会話を考えてみましょう:

ねえフランク、私は昼食をとるつもりです、私は次の会議までどれくらいの時間がありますか?
1時間

Now, let's see what that "hour" can mean in `moment`:

```js
moment.duration({hours: 0, minutes: 45}).humanize() === "an hour"
moment.duration({hours: 1, minutes: 29}).humanize() === "an hour"
```
This means that if we understand things differently I could be ~45 minutes early or late for that meeting.
  1. RTFM呼び出してくれた@sprootに感謝します

    moment.relativeTimeThreshold('m', 60);
    moment.duration({hours: 0, minutes: 45}).humanize() === "45 minutes"
    moment.duration({hours: 0, minutes: 59}).humanize() === "59 minutes"
    moment.duration({hours: 0, minutes: 60}).humanize() === "an hour"
    moment.duration({hours: 1, minutes: 29}).humanize() === "an hour"
    

    少し良いですが、休憩の長さが60分より長い場合はまだ問題があります。 その約30分の違いは、家に帰って食事をして戻ってくることができるか、近くで何かをつかまなければならないことを意味します。

  2. @Nerianhttps : //github.com/moment/moment/issues/348#issuecomment-279819773および@cogwirrelhttps : //github.com/moment/moment/issues/348#issuecomment-346233713と@sprootの組み合わせの回避策 'ヒントは、追加のライブラリを必要とせずに「十分に優れた」実装を取得します(_パーツはプレーンJSを使用して実装できます)が、直接サポートできるもののハックです。

    var el = document.createElement('script');
    el.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js";
    document.head.appendChild(el)
    moment.relativeTimeThreshold('s', 60);
    moment.relativeTimeThreshold('ss', 0); // must be after 's', disables "few seconds"
    moment.relativeTimeThreshold('m', 60);
    moment.relativeTimeThreshold('h', 24);
    moment.relativeTimeThreshold('d', 31);
    moment.relativeTimeThreshold('M', 12);
    /**
     * Return a precize human readable string representing the given moment duration.
     *
     * <strong i="34">@param</strong> {Moment.Duration} duration
     * <strong i="35">@param</strong> {{mostPreciseUnit: string, numberOfSignificantParts: integer}} options
     */
    moment.duration.fn.humanizePrecisely = function(options = {}) {
        // Split the duration into parts to be able to filter out unwanted ones
        const allParts = [
            { value: this.years(), unit: 'years' },
            { value: this.months(), unit: 'months' },
            { value: this.days(), unit: 'days' },
            { value: this.hours(), unit: 'hours' },
            { value: this.minutes(), unit: 'minutes' },
            { value: this.seconds(), unit: 'seconds' },
            // cannot format with moment.humanize()
            //{ value: duration.milliseconds(), unit: 'milliseconds' },
        ];
    
        return _(allParts)
            // only use the first parts until the most precise unit wanted
            .take(_.findIndex(allParts, {unit: options.mostPreciseUnit || 'seconds'}) + 1)
            // drop the most significant parts with a value of 0
            .dropWhile((part) => part.value === 0)
            // skip other zeroes in the middle (moment.humanize() can't format them)
            .reject((part) => part.value === 0)
            // use only the significant parts requested
            .take(options.numberOfSignificantParts || allParts.length)
            // format each part
            .map((part) => moment.duration(part.value, part.unit).locale(this.locale()).humanize())
            .join(' ');
    }
    moment.duration({hours: 2, minutes: 3, seconds: 4}).locale('de').humanizePrecisely()
        // === "2 Stunden 3 Minuten 4 seconds"
    

    (注:秒のフォーマットとロケールに問題があります。これは#4183の#3981で修正されます。)

価値があるので、私は公式ドキュメントからこれを見つけました:

https://momentjs.com/docs/#/plugins/preciserange/

私自身のコードは次のようになります-そしてそれは完璧に機能します:

    var d1 = new Date()
    var d2 = new Date(durationInMinutes * 60 * 1000)
    return moment.preciseDiff(d1 - d2)

これでこの問題は効果的に解決すると思います...?

@mercmobily for AU、US(CA)、UK:はい、ROW:実際にはそうではありません。 https://github.com/codebox/moment-precise-range/issues/6が修正されたときかもしれません。

(補足: moment*60*1000を使用することは私には少し奇妙に見えますが、 moment().add(durationInMinutes, 'minutes')を検討しましたか?)

ああ、私はモーメントにあまり精通していません! moment().add(durationInMinutes, 'minutes')は何に追加されますか?
その問題が解決されたら、それがこの問題の「解決策」だと思います...

moment()は「今」( new Date()と同様)であり、 addはそれをn分増やします。 ただし、「今」に限らず、任意のモーメントオブジェクトを使用できます。 (このすでに長い議論に焦点を合わせ続けるために、これをこのサイドノートに関連する最後のコメントとします;)

+1

+2

+1

+1

+1

これを再度開いてください。 私のソフトウェアは、あらゆる種類の時間間隔を正しく表示したいので、「12秒ごと」を「数秒ごと」に変更したり、「54秒ごと」を「1分ごと」に変更したりすることはできません。

+1

+1

私がやっている:

moment.duration('PT5S').humanize();

そして、「5秒」と言いたいのですが、代わりに「数秒」と言います。 このサポートはいつ追加できますか?

+1

+1

これは、lodashを使用しない@cogwirrelに基づく小さなユーティリティ関数です。

import { pluralize } from '...'

export function humanize (duration) {
  const durationComponents = [
    { value: duration.years(), unit: 'year' },
    { value: duration.months(), unit: 'month' },
    { value: duration.days(), unit: 'day' },
    { value: duration.hours(), unit: 'hour' },
    { value: duration.minutes(), unit: 'minute' },
    { value: duration.seconds(), unit: 'second' },
    { value: duration.milliseconds(), unit: 'millisecond' }
  ]
  return durationComponents
    .filter(({ value }) => value !== 0)
    .slice(0, 3)
    .map(({ unit, value }) => pluralize(value, unit))
    .join(', ')
}

+1

(humanize()メソッドを使用する場合、「1.51時間」を「2時間」に変換することは特に人間的ではないと思います)。

+1😞
他のライブラリは、Moment.jsのように多種多様な言語をサポートしていません。 再考してください!

+1

+1

+1

+1

PS信じられないほどまだ実装されていません;(

+1本当に、これはまだここにありませんか?!

私はついに購読を解除しました(すでに約7年になりますが、私はついにそれらすべての+1でそれを手に入れたと思います)

問題を解決するパッケージを見つけました🎉
https://github.com/EvanHahn/HumanizeDuration.js

多分それは他の誰にとっても役に立つでしょう。

+1

+1

+1

+1

その問題に対する私の見解:

const units: Array<{unit: moment.unitOfTime.Base, key: moment.RelativeTimeKey}> = [
  {unit: 'y', key: 'yy'},
  {unit: 'M', key: 'MM'},
  {unit: 'd', key: 'dd'},
  {unit: 'h', key: 'hh'},
  {unit: 'm', key: 'mm'},
  {unit: 's', key: 'ss'},
];
function accurateHumanize(duration: moment.Duration, accuracy: number = 2): string {
  let beginFilter = false;
  let componentCount = 0;

  return units
    .map(({unit, key}) => ({value: duration.get(unit), key}))
    .filter(({value, key}) => {
      if (beginFilter === false) {
        if (value === 0) {
          return false;
        }
        beginFilter = true;
      }
      componentCount++;
      return value !== 0 && componentCount <= accuracy;
    })
    .map(({value, key}) => ({value: value, key: value === 1 ? key[0] as moment.RelativeTimeKey : key}))
    .map(({value, key}) => moment.localeData().relativeTime(value, true, key, true))
    .join(', ');
}

これは非常に理にかなっています。期間の正確なフォーマットを確認したいと思います。

丸めずに人間化するオプションが大好きです
+1

これに+1

+1

+1

+1

+1

グーグルの後に誰かがここに着陸した場合に備えて、私の場合、この構成/回避策で十分でした:

moment.relativeTimeRounding((t) => {
  const DIGITS = 2; // like: 2.56 minutes
  return Math.round(t * Math.pow(10, DIGITS)) / Math.pow(10, DIGITS);
});
moment.relativeTimeThreshold('y', 365);
moment.relativeTimeThreshold('M', 12);
moment.relativeTimeThreshold('w', 4);
moment.relativeTimeThreshold('d', 31);
moment.relativeTimeThreshold('h', 24);
moment.relativeTimeThreshold('m', 60);
moment.relativeTimeThreshold('s', 60);
moment.relativeTimeThreshold('ss', 0);

console.log(moment.duration(89, 's'));
// Output: "1.48 minutes"
// … without configuring the moment.relative*(), output was: "a minute"

私の特定のユースケースでの正確さは、見栄えの良いテキストよりもはるかに重要だからです。

これは、 moment.relative*()メソッドを構成/呼び出す前後の比較です。

| 期間| 前| 後|
| --------- | --------------- | -------------- |
| 3s | a few seconds | 3 seconds |
| 44s | a few seconds | 44 seconds |
| 45s | a minute | 45 seconds |
| 1m 29s | a minute | 1.48 minutes |
| 1m 30s | 2 minutes | 1.5 minutes |
| 1m 59s | 2 minutes | 1.98 minutes |
| 44m | 44 minutes | 44 minutes |
| 45m | an hour | 45 minutes |
| 1h 29m | an hour | 1.48 hours |
| 1h 30m | 2 hours | 1.5 hours |
| 21h | 21 hours | 21 hours |
| 22h | a day | 22 hours |
| 35h | a day | 35 hours |
| 35h 30m | a day | 35.5 hours |
| 36h | 2 days | 36 hours |

このページは役に立ちましたか?
0 / 5 - 0 評価