Moment: Permintaan fitur: .humanize . yang lebih akurat

Dibuat pada 24 Jun 2012  ·  112Komentar  ·  Sumber: moment/moment

.humanize tidak terlalu akurat dalam hitungan detik.

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

Saya mengerti bahwa kita sering tidak menginginkan tingkat akurasi ini, tetapi terkadang kita menginginkan nilai yang tepat dengan cara yang dapat dibaca manusia.

Saya menyarankan perubahan pada API (yang tampaknya kompatibel dengan yang sebenarnya saya lihat) untuk mendukung fitur ini:

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"

Bagaimana menurutmu ?

Enhancement New Feature

Komentar yang paling membantu

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

Akan menyenangkan untuk memiliki output yang tepat seperti: 3 jam dan 3 detik.

Semua 112 komentar

@FGRibreau , masalah ini muncul di #232, dan OP di sana tampaknya baik-baik saja tidak menambahkannya ke inti.

Anda bisa menulis definisi bahasa yang disebut precise-english atau sesuatu ketika Anda ingin waktu relatif yang lebih tepat. Dengan fitur instance lang baru yang keluar di 1.7.0, ini bisa sangat berguna. Saat ini definisi bahasa apa pun akan mewarisi semua nilai yang tidak ditentukan dari bahasa Inggris, jadi Anda hanya perlu mengubah kamus relativeTime. Sayangnya, warisan tidak mewarisi dalam kamus, jadi Anda harus menentukan seluruh kamus.

Harap diperhatikan: metode yang dijelaskan di #232 tidak akan berfungsi lagi di 1.7.0, karena perubahan di #332.

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

Satu hal yang akan mempermudah ini adalah agar pewarisan berfungsi sehingga Anda hanya perlu menentukan satu nilai saja di dalam objek relativeTime . @timrwood , apakah menurut Anda kami membutuhkan warisan _smarter_?

Jika kita menambahkan warisan yang lebih cerdas, saya mungkin ingin melakukan sesuatu seperti yang dilakukan CLDR dan membuat setiap sub-bahasa mewarisi dari bahasa master. Jadi fr_CA akan mewarisi dari fr dan en_GB akan mewarisi dari en .

Saya tidak berpikir kita perlu melakukan perluasan mendalam untuk mengganti hanya 'relativeTime.s'.

@FGRibreau melakukan sesuatu di sepanjang baris definisi bahasa precise-en bekerja untuk Anda?

Menutup ini sebagai solusi @rockymeza adalah cara yang lebih disukai untuk menangani ini.

Ini berlaku untuk lebih dari sekadar detik. Hal yang sama berlaku untuk jam, tahun, dll...

Ya, dan solusi yang lebih disukai hanya untuk auditori berbahasa Inggris. Dalam bahasa lain Anda harus repot dengan infleksi kata benda (deklensi).

Saya menambahkan bobot untuk masalah ini. Saat merancang hitungan mundur, presisi diperlukan.

Jadi tidak apa-apa untuk memiliki "10 jam yang lalu" ketika melihat hal-hal masa lalu, tetapi jika dengan sabar menunggu suatu peristiwa, saya ingin "dalam 10 jam 3 menit 8 detik"

Jangan bilang bahwa saya harus menulis bahasa khusus untuk mendapatkannya?

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

Akan menyenangkan untuk memiliki output yang tepat seperti: 3 jam dan 3 detik.

Saya ingin fitur ini juga.

Saya juga membutuhkan versi manusiawi yang tepat!

Saya juga berpikir akan lebih baik untuk memanusiakan Moment (opsional) lebih tepat, tetapi bagi siapa saja yang datang ke sini mencari solusi sekarang, saya telah menemukan bahwa HumanizeDuration.js bekerja dengan cukup baik:

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'

Akan senang melihat opsi "manusiawi yang akurat", harus menggunakan perpustakaan tambahan di atas momen sedikit kikuk..

+1 untuk memanusiakan yang tepat!

Sangat kecewa melihat bahwa tidak ada pilihan untuk mendapatkan durasi manusiawi yang tepat. :|

Ada beberapa plugin bernama Precise Range yang dirujuk dalam dokumen. Apakah ada yang mencobanya?

Rentang Tepat secara teknis berfungsi, tetapi tampaknya mengembalikan string alih-alih objek momen, jadi saya tidak dapat memilih secara spesifik bagian tanggal apa yang mungkin saya sukai.

Bahasa (imo) juga agak salah, salah satu hasilnya adalah - 'an hour 19 minutes abeberapa detik' . Saya lebih suka melihat sesuatu seperti 1 jam 19 menit dan beberapa detik. Mencampur kata-kata dan angka selalu sedikit tata bahasa tidak-tidak (sejauh yang saya tahu).

+1 untuk memanusiakan momen yang tepat

@Envek Rentang Tepat tampaknya bagus, tidak mendukung i18n/l10n apa pun ...

Dukungan resmi oleh moment.js akan menyenangkan karena saya membutuhkan ini setidaknya dalam dua atau tiga proyek saya.

@topaxi +1

+1

@doingweb Saya mengonfirmasi bahwa modul HumanizeDuration.js berfungsi dengan baik!

+1 untuk memanusiakan momen yang tepat

+1 untuk memanusiakan momen yang lebih tepat

+1

+1

+1

+1

+1

+1

+1

Mengapa ini selalu ditutup? Ini adalah fitur paling jelas yang harus diimplementasikan di moment.js. Saya benar-benar terkejut bahwa itu belum ada. Memanusiakan sama sekali tidak berguna di mana pun selain tampilan waktu yang tidak jelas seperti di posting di forum tanpa itu.

+1

+1

+1

-1. Saya suka memanusiakan cara kerjanya sekarang. Seharusnya memberikan versi durasi yang "ramah manusia".

"Hei Frank, kapan kamu mengirim email itu?"
"Sekitar satu menit yang lalu."

vs

"Hei Frank, kapan kamu mengirim email itu?"
"Empat puluh tiga detik yang lalu."

Mana yang lebih terlihat "manusiawi?"

Versi yang lebih akurat tidak seharusnya menggantikan yang sekarang. Ini adalah permintaan untuk fitur baru.

+1, @mattgrande sementara apa yang kita miliki sekarang bagus untuk menggambarkan durasi sesuatu di masa lalu, itu tidak tepat untuk menggambarkan, misalnya panjang janji, misalnya "1 jam, 30 menit".

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1 untuk ini dari saya. Membuat definisi bahasa baru, atau memodifikasi yang sudah ada, tidak benar-benar berfungsi. Sepertinya ada 108 bahasa yang saat ini didukung oleh Momen, jadi kita harus mengubah 108 definisi secara manual (dan berharap semuanya benar secara tata bahasa), atau melupakan pengguna yang tidak bisa berbahasa Inggris? Tak satu pun dari itu terdengar seperti solusi yang baik ...

Saya menggunakan ini:

````javascript
var humanizeDuration = function(eventDuration){
eventMDuration = momen.duration(eventDuration, 'detik');
eventDurationString = ""
jika (eventMDuration.days() > 0)
eventDurationString += " " + moment.duration(eventMDuration.days(), 'hari').humanize()
jika (eventMDuration.hours() > 0)
eventDurationString += " " + moment.duration(eventMDuration.hours(), 'hours').humanize()
jika (eventMDuration.minutes() > 0)
eventDurationString += " " + moment.duration(eventMDuration.minutes(), 'minutes').humanize()

kembali eventDurationString.trim()
}
````

+1

+1 tanpa fitur ini, pelacakan waktu tidak dimungkinkan.

Mengapa masalah ditutup?

+1

+1

+1

Kemampuan untuk menambahkan opsi yang lebih tepat, sementara opsi masih 'manusia' akan sangat berharga.

+1

+1

+1

+1

+1. Pengerjaan aplikasi akuntansi yang mengharuskan untuk menampilkan durasi secara akurat tetapi dalam format manusia. "1 tahun, 2 bulan, 3 hari" lebih baik daripada "398 hari", namun "1 tahun" tidak terlalu dapat diterima.

Implementasi saat ini sangat manusiawi sehingga pada dasarnya tidak berguna.

+1

duration.humanize memiliki ambang batas yang menentukan kapan suatu unit dianggap sebagai satu menit, satu jam, dan seterusnya. Misalnya, secara default lebih dari 45 detik dianggap satu menit, lebih dari 22 jam dianggap sehari dan seterusnya. Untuk mengubah cutoff tersebut gunakan moment.relativeTimeThreshold(unit, limit) di mana unit adalah salah satu dari ss , s , m , h , d , M .

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

+1

+1

+1, harap pertimbangkan kembali untuk membuka masalah ini 😍

+1

+1

+1

+1

+1

+1

Saya menggunakan sesuatu seperti ini:

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"

Menggunakan lodash dan pluralize .

@timrwood kasus untuk mengimplementasikan ini:

  1. @rockymeza 's https://github.com/moment/moment/issues/348#issuecomment -6535794 solusi berarti kami (setiap pengembang di luar sana) harus menerapkan kembali ini dalam setiap bahasa yang mereka dukung, meskipun Anda dan Anda kontributor telah melakukan pekerjaan luar biasa dalam menerjemahkan ke banyak bahasa
  2. @mattgrande https://github.com/moment/moment/issues/348#issuecomment -237830415 argumen bahwa itu sudah cukup manusiawi, hanya menyebut bagian yang berfungsi dengan baik. Pertimbangkan percakapan ini:

Hei Frank, saya akan makan siang, berapa banyak waktu yang saya miliki sampai pertemuan berikutnya?
satu jam

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. Terima kasih kepada @sproot karena telah memanggil RTFM

    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"
    

    Sedikit lebih baik, tetapi masih bermasalah ketika durasi istirahat lebih dari 60 menit. Perbedaan ~30 menit itu bisa berarti saya bisa pulang, makan dan kembali, atau saya harus mengambil sesuatu di dekatnya.

  2. Solusi dari @Nerian https://github.com/moment/moment/issues/348#issuecomment -279819773 dan @cogwirrel https://github.com/moment/moment/issues/348#issuecomment -346233713 dikombinasikan dengan @sproot ' s tip mendapatkan implementasi "cukup baik" tanpa memerlukan pustaka tambahan (_ bagian dapat diimplementasikan menggunakan JS biasa), tetapi ini adalah peretasan untuk sesuatu yang dapat didukung secara langsung:

    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"
    

    (Catatan: Ada yang salah dengan pemformatan detik dan lokal, yang akan diperbaiki oleh #3981 di #4183.)

Untuk apa nilainya, saya baru saja menemukan ini dari dokumentasi resmi:

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

Kode saya sendiri terlihat seperti ini -- dan berfungsi dengan baik:

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

Saya kira ini secara efektif menutup masalah ini ...?

@mercmobily untuk AU, US (CA), UK: ya, ROW: tidak juga; mungkin ketika https://github.com/codebox/moment-precise-range/issues/6 diperbaiki.

(Catatan: menggunakan moment dan *60*1000 terlihat agak aneh bagi saya, apakah Anda sudah mempertimbangkan moment().add(durationInMinutes, 'minutes') ?)

Ah, saya tidak terlalu berpengalaman dalam Moment! Apa yang ditambahkan moment().add(durationInMinutes, 'minutes') ?
Saya pikir begitu masalah itu ditutup, itulah "solusi" untuk masalah ini ...

moment() adalah "sekarang" (mirip dengan new Date() ), dan add meningkatkannya sebesar n menit. Objek momen apa pun dapat digunakan, tidak terbatas pada "sekarang". (Agar diskusi yang sudah panjang ini tetap fokus, biarkan ini menjadi komentar terakhir terkait dengan sidenote ini;)

+1

+2

+1

+1

+1

Silakan buka kembali ini. Perangkat lunak saya ingin menunjukkan interval waktu apa pun dengan benar, dan mengubah "setiap 12 detik" menjadi "setiap beberapa detik" atau mengubah "setiap 54 detik" menjadi "setiap menit" tidak dapat diterima.

+1

+1

Aku melakukan:

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

Dan saya ingin mengatakan: '5 detik' tetapi malah mengatakan 'beberapa detik'. Kapan kami dapat menambahkan dukungan ini?

+1

+1

Inilah fungsi utilitas kecil berdasarkan @cogwirrel yang tidak menggunakan lodash

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

(Saya berpendapat bahwa jika Anda akan memiliki metode humanize() , maka mengonversi "1,51 jam" menjadi "2 jam" tidak terlalu manusiawi).

+1
Pustaka lain tidak mendukung berbagai macam bahasa seperti yang dilakukan Moment.js. Harap pertimbangkan kembali!

+1

+1

+1

+1

PS luar biasa itu belum diterapkan ;(

+1 sungguh, ini masih belum ada di sini ?!

Saya akhirnya berhenti berlangganan (kira-kira sudah 7 tahun, tapi saya pikir saya akhirnya memiliki semua +1 itu)

Saya menemukan paket yang menyelesaikan masalah saya
https://github.com/EvanHahn/HumanizeDuration.js

Mungkin itu berguna untuk orang lain juga.

+1

+1

+1

+1

Pendapat saya tentang masalah itu:

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

Ini sangat masuk akal, akan senang melihat format durasi yang tepat.

Akan menyukai pilihan untuk memanusiakan tanpa pembulatan
+1

+1 pada ini

+1

+1

+1

+1

Kalau-kalau ada yang mendarat di sini setelah googling, konfigurasi/solusi ini sudah cukup dalam kasus saya:

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"

karena akurasi dalam kasus penggunaan khusus saya jauh lebih penting daripada teks yang terlihat bagus.

Ini adalah perbandingan sebelum dan sesudah mengkonfigurasi/memanggil metode moment.relative*() :

| durasi | sebelum | setelah |
| --------- | --------------- | -------------- |
| 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 |

Apakah halaman ini membantu?
0 / 5 - 0 peringkat