mirror of
https://git.meli.delivery/meli/meli
synced 2024-11-19 03:25:38 +00:00
melib: add datetime module
Datetime module adds POSIX time functions interface
This commit is contained in:
parent
f6de511abd
commit
c0ac643f05
@ -22,7 +22,7 @@
|
|||||||
#[cfg(feature = "vcard")]
|
#[cfg(feature = "vcard")]
|
||||||
pub mod vcard;
|
pub mod vcard;
|
||||||
|
|
||||||
use chrono::{DateTime, Local};
|
use crate::datetime::{self, UnixTimestamp};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@ -59,8 +59,8 @@ impl From<String> for CardId {
|
|||||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct AddressBook {
|
pub struct AddressBook {
|
||||||
display_name: String,
|
display_name: String,
|
||||||
created: DateTime<Local>,
|
created: UnixTimestamp,
|
||||||
last_edited: DateTime<Local>,
|
last_edited: UnixTimestamp,
|
||||||
pub cards: FnvHashMap<CardId, Card>,
|
pub cards: FnvHashMap<CardId, Card>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,13 +73,13 @@ pub struct Card {
|
|||||||
name_prefix: String,
|
name_prefix: String,
|
||||||
name_suffix: String,
|
name_suffix: String,
|
||||||
//address
|
//address
|
||||||
birthday: Option<DateTime<Local>>,
|
birthday: Option<UnixTimestamp>,
|
||||||
email: String,
|
email: String,
|
||||||
url: String,
|
url: String,
|
||||||
key: String,
|
key: String,
|
||||||
|
|
||||||
color: u8,
|
color: u8,
|
||||||
last_edited: DateTime<Local>,
|
last_edited: UnixTimestamp,
|
||||||
extra_properties: FnvHashMap<String, String>,
|
extra_properties: FnvHashMap<String, String>,
|
||||||
|
|
||||||
/// If true, we can't make any changes because we do not manage this resource.
|
/// If true, we can't make any changes because we do not manage this resource.
|
||||||
@ -90,8 +90,8 @@ impl AddressBook {
|
|||||||
pub fn new(display_name: String) -> AddressBook {
|
pub fn new(display_name: String) -> AddressBook {
|
||||||
AddressBook {
|
AddressBook {
|
||||||
display_name,
|
display_name,
|
||||||
created: Local::now(),
|
created: datetime::now(),
|
||||||
last_edited: Local::now(),
|
last_edited: datetime::now(),
|
||||||
cards: FnvHashMap::default(),
|
cards: FnvHashMap::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,7 +154,7 @@ impl Card {
|
|||||||
url: String::new(),
|
url: String::new(),
|
||||||
key: String::new(),
|
key: String::new(),
|
||||||
|
|
||||||
last_edited: Local::now(),
|
last_edited: datetime::now(),
|
||||||
external_resource: false,
|
external_resource: false,
|
||||||
extra_properties: FnvHashMap::default(),
|
extra_properties: FnvHashMap::default(),
|
||||||
color: 0,
|
color: 0,
|
||||||
@ -190,7 +190,7 @@ impl Card {
|
|||||||
self.key.as_str()
|
self.key.as_str()
|
||||||
}
|
}
|
||||||
pub fn last_edited(&self) -> String {
|
pub fn last_edited(&self) -> String {
|
||||||
self.last_edited.to_rfc2822()
|
datetime::timestamp_to_string(self.last_edited, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_id(&mut self, new_val: CardId) {
|
pub fn set_id(&mut self, new_val: CardId) {
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
/// Convert VCard strings to meli Cards (contacts).
|
/// Convert VCard strings to meli Cards (contacts).
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::chrono::TimeZone;
|
|
||||||
use crate::error::{MeliError, Result};
|
use crate::error::{MeliError, Result};
|
||||||
use crate::parsec::{match_literal_anycase, one_or_more, peek, prefix, take_until, Parser};
|
use crate::parsec::{match_literal_anycase, one_or_more, peek, prefix, take_until, Parser};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
@ -202,7 +201,7 @@ impl<V: VCardVersion> TryInto<Card> for VCard<V> {
|
|||||||
T102200Z
|
T102200Z
|
||||||
T102200-0800
|
T102200-0800
|
||||||
*/
|
*/
|
||||||
card.birthday = chrono::Local.datetime_from_str(&val.value, "%Y%m%d").ok();
|
card.birthday = crate::datetime::timestamp_from_string(val.value.as_str(), "%Y%m%d");
|
||||||
}
|
}
|
||||||
if let Some(val) = self.0.remove("EMAIL") {
|
if let Some(val) = self.0.remove("EMAIL") {
|
||||||
card.set_email(val.value);
|
card.set_email(val.value);
|
||||||
|
131
melib/src/datetime.rs
Normal file
131
melib/src/datetime.rs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* meli - melib POSIX libc time interface
|
||||||
|
*
|
||||||
|
* Copyright 2020 Manos Pitsidianakis
|
||||||
|
*
|
||||||
|
* This file is part of meli.
|
||||||
|
*
|
||||||
|
* meli is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* meli is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
|
||||||
|
pub type UnixTimestamp = u64;
|
||||||
|
|
||||||
|
use libc::{timeval, timezone};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn strptime(
|
||||||
|
s: *const ::std::os::raw::c_char,
|
||||||
|
format: *const ::std::os::raw::c_char,
|
||||||
|
tm: *mut ::libc::tm,
|
||||||
|
) -> *const ::std::os::raw::c_char;
|
||||||
|
|
||||||
|
fn strftime(
|
||||||
|
s: *mut ::std::os::raw::c_char,
|
||||||
|
max: ::libc::size_t,
|
||||||
|
format: *const ::std::os::raw::c_char,
|
||||||
|
tm: *const ::libc::tm,
|
||||||
|
) -> ::libc::size_t;
|
||||||
|
|
||||||
|
fn mktime(tm: *const ::libc::tm) -> ::libc::time_t;
|
||||||
|
|
||||||
|
fn localtime_r(timep: *const ::libc::time_t, tm: *mut ::libc::tm) -> *mut ::libc::tm;
|
||||||
|
|
||||||
|
fn gettimeofday(tv: *mut timeval, tz: *mut timezone) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn timestamp_to_string(timestamp: UnixTimestamp, fmt: Option<&str>) -> String {
|
||||||
|
let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() };
|
||||||
|
unsafe {
|
||||||
|
let i: i64 = timestamp.try_into().unwrap_or(0);
|
||||||
|
localtime_r(&i as *const i64, &mut new_tm as *mut ::libc::tm);
|
||||||
|
}
|
||||||
|
let fmt = fmt.map(|slice| CString::new(slice).unwrap());
|
||||||
|
let format: &CStr = if let Some(ref s) = fmt {
|
||||||
|
&s
|
||||||
|
} else {
|
||||||
|
unsafe { CStr::from_bytes_with_nul_unchecked(b"%a, %d %b %Y %T %z\0") }
|
||||||
|
};
|
||||||
|
let s: CString;
|
||||||
|
unsafe {
|
||||||
|
let mut vec: Vec<u8> = vec![0; 256];
|
||||||
|
let ret = strftime(
|
||||||
|
vec.as_mut_ptr() as *mut _,
|
||||||
|
256,
|
||||||
|
format.as_ptr(),
|
||||||
|
&new_tm as *const _,
|
||||||
|
);
|
||||||
|
s = CString::new(&vec[0..ret]).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
s.to_string_lossy().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rfc822_to_timestamp<T>(s: T) -> UnixTimestamp
|
||||||
|
where
|
||||||
|
T: Into<Vec<u8>>,
|
||||||
|
{
|
||||||
|
let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() };
|
||||||
|
unsafe {
|
||||||
|
let fmt = CStr::from_bytes_with_nul_unchecked(b"%a, %e %h %Y %H:%M:%S %z\0");
|
||||||
|
let ret = strptime(
|
||||||
|
CString::new(s).unwrap().as_ptr(),
|
||||||
|
fmt.as_ptr(),
|
||||||
|
&mut new_tm as *mut _,
|
||||||
|
);
|
||||||
|
if ret.is_null() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return mktime(&new_tm as *const _) as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn timestamp_from_string<T>(s: T, fmt: &str) -> Option<UnixTimestamp>
|
||||||
|
where
|
||||||
|
T: Into<Vec<u8>>,
|
||||||
|
{
|
||||||
|
let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() };
|
||||||
|
let fmt = CString::new(fmt).unwrap();
|
||||||
|
unsafe {
|
||||||
|
let ret = strptime(
|
||||||
|
CString::new(s).unwrap().as_ptr(),
|
||||||
|
fmt.as_ptr(),
|
||||||
|
&mut new_tm as *mut _,
|
||||||
|
);
|
||||||
|
if ret.is_null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some(mktime(&new_tm as *const _) as u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn now() -> UnixTimestamp {
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
let mut tv = MaybeUninit::<::libc::timeval>::uninit();
|
||||||
|
let mut tz = MaybeUninit::<::libc::timezone>::uninit();
|
||||||
|
unsafe {
|
||||||
|
let ret = gettimeofday(tv.as_mut_ptr(), tz.as_mut_ptr());
|
||||||
|
if ret == -1 {
|
||||||
|
unreachable!("gettimeofday returned -1");
|
||||||
|
}
|
||||||
|
(tv.assume_init()).tv_sec as UnixTimestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_timestamp() {
|
||||||
|
timestamp_to_string(0);
|
||||||
|
}
|
@ -39,6 +39,7 @@ pub use address::*;
|
|||||||
pub mod signatures;
|
pub mod signatures;
|
||||||
|
|
||||||
use crate::backends::BackendOp;
|
use crate::backends::BackendOp;
|
||||||
|
use crate::datetime::UnixTimestamp;
|
||||||
use crate::error::{MeliError, Result};
|
use crate::error::{MeliError, Result};
|
||||||
use crate::thread::ThreadHash;
|
use crate::thread::ThreadHash;
|
||||||
|
|
||||||
@ -51,9 +52,6 @@ use std::option::Option;
|
|||||||
use std::str;
|
use std::str;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
|
|
||||||
use chrono;
|
|
||||||
use chrono::TimeZone;
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
pub struct Flag: u8 {
|
pub struct Flag: u8 {
|
||||||
@ -105,7 +103,6 @@ impl EnvelopeWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type UnixTimestamp = u64;
|
|
||||||
pub type EnvelopeHash = u64;
|
pub type EnvelopeHash = u64;
|
||||||
|
|
||||||
/// `Envelope` represents all the data of an email we need to know.
|
/// `Envelope` represents all the data of an email we need to know.
|
||||||
@ -350,14 +347,10 @@ impl Envelope {
|
|||||||
self.timestamp
|
self.timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn datetime(&self) -> chrono::DateTime<chrono::FixedOffset> {
|
pub fn datetime(&self) -> UnixTimestamp {
|
||||||
if let Ok(d) = parser::date(&self.date.as_bytes()) {
|
self.timestamp
|
||||||
return d;
|
|
||||||
}
|
|
||||||
chrono::FixedOffset::west(0)
|
|
||||||
.ymd(1970, 1, 1)
|
|
||||||
.and_hms(0, 0, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn date_as_str(&self) -> &str {
|
pub fn date_as_str(&self) -> &str {
|
||||||
&self.date
|
&self.date
|
||||||
}
|
}
|
||||||
@ -572,8 +565,8 @@ impl Envelope {
|
|||||||
pub fn set_thread(&mut self, new_val: ThreadHash) {
|
pub fn set_thread(&mut self, new_val: ThreadHash) {
|
||||||
self.thread = new_val;
|
self.thread = new_val;
|
||||||
}
|
}
|
||||||
pub fn set_datetime(&mut self, new_val: chrono::DateTime<chrono::FixedOffset>) {
|
pub fn set_datetime(&mut self, new_val: UnixTimestamp) {
|
||||||
self.timestamp = new_val.timestamp() as UnixTimestamp;
|
self.timestamp = new_val;
|
||||||
}
|
}
|
||||||
pub fn set_flag(
|
pub fn set_flag(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -2,7 +2,6 @@ use super::*;
|
|||||||
use crate::backends::BackendOp;
|
use crate::backends::BackendOp;
|
||||||
use crate::email::attachments::AttachmentBuilder;
|
use crate::email::attachments::AttachmentBuilder;
|
||||||
use crate::shellexpand::ShellExpandTrait;
|
use crate::shellexpand::ShellExpandTrait;
|
||||||
use chrono::{DateTime, Local};
|
|
||||||
use data_encoding::BASE64_MIME;
|
use data_encoding::BASE64_MIME;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
@ -35,8 +34,10 @@ impl Default for Draft {
|
|||||||
headers.insert("Cc".into(), "".into());
|
headers.insert("Cc".into(), "".into());
|
||||||
headers.insert("Bcc".into(), "".into());
|
headers.insert("Bcc".into(), "".into());
|
||||||
|
|
||||||
let now: DateTime<Local> = Local::now();
|
headers.insert(
|
||||||
headers.insert("Date".into(), now.to_rfc2822());
|
"Date".into(),
|
||||||
|
crate::datetime::timestamp_to_string(crate::datetime::now(), None),
|
||||||
|
);
|
||||||
headers.insert("Subject".into(), "".into());
|
headers.insert("Subject".into(), "".into());
|
||||||
headers.insert(
|
headers.insert(
|
||||||
"User-Agent".into(),
|
"User-Agent".into(),
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
use super::*;
|
use super::*;
|
||||||
use chrono;
|
|
||||||
use data_encoding::BASE64_MIME;
|
use data_encoding::BASE64_MIME;
|
||||||
use encoding::{DecoderTrap, Encoding};
|
use encoding::{DecoderTrap, Encoding};
|
||||||
use nom::{is_hex_digit, le_u8};
|
use nom::{is_hex_digit, le_u8};
|
||||||
@ -658,18 +657,13 @@ fn eat_comments(input: &[u8]) -> Vec<u8> {
|
|||||||
* right now we expect input will have no extra spaces in between tokens
|
* right now we expect input will have no extra spaces in between tokens
|
||||||
*
|
*
|
||||||
* We should use a custom parser here*/
|
* We should use a custom parser here*/
|
||||||
pub fn date(input: &[u8]) -> Result<chrono::DateTime<chrono::FixedOffset>> {
|
pub fn date(input: &[u8]) -> Result<UnixTimestamp> {
|
||||||
let mut parsed_result = phrase(&eat_comments(input)).to_full_result()?;
|
let mut parsed_result = phrase(&eat_comments(input)).to_full_result()?;
|
||||||
if let Some(pos) = parsed_result.find(b"-0000") {
|
if let Some(pos) = parsed_result.find(b"-0000") {
|
||||||
parsed_result[pos] = b'+';
|
parsed_result[pos] = b'+';
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(
|
Ok(crate::datetime::rfc822_to_timestamp(parsed_result.trim()))
|
||||||
chrono::DateTime::parse_from_rfc2822(
|
|
||||||
String::from_utf8_lossy(parsed_result.trim()).as_ref(),
|
|
||||||
)
|
|
||||||
.map_err(|err| MeliError::new(err.to_string()))?,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
named!(pub message_id<&[u8]>,
|
named!(pub message_id<&[u8]>,
|
||||||
|
@ -104,6 +104,9 @@ pub mod dbg {
|
|||||||
#[cfg(feature = "unicode_algorithms")]
|
#[cfg(feature = "unicode_algorithms")]
|
||||||
extern crate text_processing;
|
extern crate text_processing;
|
||||||
|
|
||||||
|
pub mod datetime;
|
||||||
|
pub use datetime::UnixTimestamp;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod logging;
|
mod logging;
|
||||||
pub use self::logging::LoggingLevel::*;
|
pub use self::logging::LoggingLevel::*;
|
||||||
@ -129,7 +132,6 @@ extern crate serde_derive;
|
|||||||
/* parser */
|
/* parser */
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate nom;
|
extern crate nom;
|
||||||
extern crate chrono;
|
|
||||||
extern crate data_encoding;
|
extern crate data_encoding;
|
||||||
extern crate encoding;
|
extern crate encoding;
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::shellexpand::ShellExpandTrait;
|
use crate::shellexpand::ShellExpandTrait;
|
||||||
use chrono::offset::Local;
|
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{BufWriter, Write};
|
use std::io::{BufWriter, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -79,7 +78,9 @@ pub fn log(val: String, level: LoggingLevel) {
|
|||||||
let mut b = f.lock().unwrap();
|
let mut b = f.lock().unwrap();
|
||||||
if level <= b.level {
|
if level <= b.level {
|
||||||
b.dest
|
b.dest
|
||||||
.write_all(Local::now().to_string().as_bytes())
|
.write_all(
|
||||||
|
crate::datetime::timestamp_to_string(crate::datetime::now(), None).as_bytes(),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
b.dest.write_all(b" [").unwrap();
|
b.dest.write_all(b" [").unwrap();
|
||||||
b.dest.write_all(level.to_string().as_bytes()).unwrap();
|
b.dest.write_all(level.to_string().as_bytes()).unwrap();
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
* ownership.
|
* ownership.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::datetime::UnixTimestamp;
|
||||||
use crate::email::parser::BytesExt;
|
use crate::email::parser::BytesExt;
|
||||||
use crate::email::*;
|
use crate::email::*;
|
||||||
use crate::structs::StackVec;
|
use crate::structs::StackVec;
|
||||||
@ -432,13 +433,6 @@ impl ThreadNode {
|
|||||||
self.date
|
self.date
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn datetime(&self) -> chrono::DateTime<chrono::Utc> {
|
|
||||||
use chrono::{TimeZone, Utc};
|
|
||||||
use std::convert::TryInto;
|
|
||||||
|
|
||||||
Utc.timestamp(self.date.try_into().unwrap_or(0), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.parent.is_none() && self.message.is_none() && self.children.is_empty()
|
self.parent.is_none() && self.message.is_none() && self.children.is_empty()
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use melib::email::UnixTimestamp;
|
|
||||||
use melib::parsec::*;
|
use melib::parsec::*;
|
||||||
|
use melib::UnixTimestamp;
|
||||||
use melib::{
|
use melib::{
|
||||||
backends::{FolderHash, MailBackend},
|
backends::{FolderHash, MailBackend},
|
||||||
email::EnvelopeHash,
|
email::EnvelopeHash,
|
||||||
|
@ -911,10 +911,7 @@ impl ConversationsListing {
|
|||||||
n / (24 * 60 * 60),
|
n / (24 * 60 * 60),
|
||||||
if n / (24 * 60 * 60) == 1 { "" } else { "s" }
|
if n / (24 * 60 * 60) == 1 { "" } else { "s" }
|
||||||
),
|
),
|
||||||
_ => thread_node
|
_ => melib::datetime::timestamp_to_string(thread_node.date(), Some("%Y-%m-%d %T")),
|
||||||
.datetime()
|
|
||||||
.format("%Y-%m-%d %H:%M:%S")
|
|
||||||
.to_string(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,7 +906,7 @@ impl PlainListing {
|
|||||||
n if n < 4 * 24 * 60 * 60 => {
|
n if n < 4 * 24 * 60 * 60 => {
|
||||||
format!("{} days ago{}", n / (24 * 60 * 60), " ".repeat(9))
|
format!("{} days ago{}", n / (24 * 60 * 60), " ".repeat(9))
|
||||||
}
|
}
|
||||||
_ => envelope.datetime().format("%Y-%m-%d %H:%M:%S").to_string(),
|
_ => melib::datetime::timestamp_to_string(envelope.datetime(), None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +487,7 @@ impl ThreadListing {
|
|||||||
n if n < 4 * 24 * 60 * 60 => {
|
n if n < 4 * 24 * 60 * 60 => {
|
||||||
format!("{} days ago{}", n / (24 * 60 * 60), " ".repeat(9))
|
format!("{} days ago{}", n / (24 * 60 * 60), " ".repeat(9))
|
||||||
}
|
}
|
||||||
_ => envelope.datetime().format("%Y-%m-%d %H:%M:%S").to_string(),
|
_ => melib::datetime::timestamp_to_string(envelope.datetime(), None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user