mirror of
https://github.com/Llewellynvdm/exa.git
synced 2025-02-05 12:08:24 +00:00
Merge pull request #670 from Freaky/fix-pre-epoch-times
Handle timestamps before UNIX_EPOCH (#658)
This commit is contained in:
commit
4b459631aa
@ -4,7 +4,7 @@ use std::io::Error as IOError;
|
|||||||
use std::io::Result as IOResult;
|
use std::io::Result as IOResult;
|
||||||
use std::os::unix::fs::{MetadataExt, PermissionsExt, FileTypeExt};
|
use std::os::unix::fs::{MetadataExt, PermissionsExt, FileTypeExt};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::{UNIX_EPOCH, Duration};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
|
|
||||||
@ -325,36 +325,36 @@ impl<'dir> File<'dir> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This file’s last modified timestamp.
|
/// This file’s last modified timestamp, if available on this platform.
|
||||||
/// If the file's time is invalid, assume it was modified today
|
pub fn modified_time(&self) -> Option<SystemTime> {
|
||||||
pub fn modified_time(&self) -> Duration {
|
self.metadata.modified().ok()
|
||||||
match self.metadata.modified() {
|
|
||||||
Ok(system_time) => system_time.duration_since(UNIX_EPOCH).unwrap(),
|
|
||||||
Err(_) => Duration::new(0, 0),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This file’s last changed timestamp.
|
/// This file’s last changed timestamp, if available on this platform.
|
||||||
pub fn changed_time(&self) -> Duration {
|
pub fn changed_time(&self) -> Option<SystemTime> {
|
||||||
Duration::new(self.metadata.ctime() as u64, self.metadata.ctime_nsec() as u32)
|
let (mut sec, mut nsec) = (self.metadata.ctime(), self.metadata.ctime_nsec());
|
||||||
|
|
||||||
|
Some(
|
||||||
|
if sec < 0 {
|
||||||
|
if nsec > 0 {
|
||||||
|
sec += 1;
|
||||||
|
nsec = nsec - 1_000_000_000;
|
||||||
|
}
|
||||||
|
UNIX_EPOCH - Duration::new(sec.abs() as u64, nsec.abs() as u32)
|
||||||
|
} else {
|
||||||
|
UNIX_EPOCH + Duration::new(sec as u64, nsec as u32)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This file’s last accessed timestamp.
|
/// This file’s last accessed timestamp, if available on this platform.
|
||||||
/// If the file's time is invalid, assume it was accessed today
|
pub fn accessed_time(&self) -> Option<SystemTime> {
|
||||||
pub fn accessed_time(&self) -> Duration {
|
self.metadata.accessed().ok()
|
||||||
match self.metadata.accessed() {
|
|
||||||
Ok(system_time) => system_time.duration_since(UNIX_EPOCH).unwrap(),
|
|
||||||
Err(_) => Duration::new(0, 0),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This file’s created timestamp.
|
/// This file’s created timestamp, if available on this platform.
|
||||||
/// If the file's time is invalid, assume it was created today
|
pub fn created_time(&self) -> Option<SystemTime> {
|
||||||
pub fn created_time(&self) -> Duration {
|
self.metadata.created().ok()
|
||||||
match self.metadata.created() {
|
|
||||||
Ok(system_time) => system_time.duration_since(UNIX_EPOCH).unwrap(),
|
|
||||||
Err(_) => Duration::new(0, 0),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This file’s ‘type’.
|
/// This file’s ‘type’.
|
||||||
|
@ -11,18 +11,21 @@ pub trait Render {
|
|||||||
format: &TimeFormat) -> TextCell;
|
format: &TimeFormat) -> TextCell;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for std::time::Duration {
|
impl Render for Option<std::time::SystemTime> {
|
||||||
fn render(self, style: Style,
|
fn render(self, style: Style,
|
||||||
tz: &Option<TimeZone>,
|
tz: &Option<TimeZone>,
|
||||||
format: &TimeFormat) -> TextCell {
|
format: &TimeFormat) -> TextCell {
|
||||||
|
|
||||||
if let Some(ref tz) = *tz {
|
let datestamp = if let Some(time) = self {
|
||||||
let datestamp = format.format_zoned(self, tz);
|
if let Some(ref tz) = tz {
|
||||||
TextCell::paint(style, datestamp)
|
format.format_zoned(time, tz)
|
||||||
}
|
} else {
|
||||||
else {
|
format.format_local(time)
|
||||||
let datestamp = format.format_local(self);
|
}
|
||||||
TextCell::paint(style, datestamp)
|
} else {
|
||||||
}
|
String::from("-")
|
||||||
|
};
|
||||||
|
|
||||||
|
TextCell::paint(style, datestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Timestamp formatting.
|
//! Timestamp formatting.
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece};
|
use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece};
|
||||||
use datetime::fmt::DateFormat;
|
use datetime::fmt::DateFormat;
|
||||||
@ -51,7 +51,7 @@ pub enum TimeFormat {
|
|||||||
// timestamps are separate types.
|
// timestamps are separate types.
|
||||||
|
|
||||||
impl TimeFormat {
|
impl TimeFormat {
|
||||||
pub fn format_local(&self, time: Duration) -> String {
|
pub fn format_local(&self, time: SystemTime) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
TimeFormat::DefaultFormat(ref fmt) => fmt.format_local(time),
|
TimeFormat::DefaultFormat(ref fmt) => fmt.format_local(time),
|
||||||
TimeFormat::ISOFormat(ref iso) => iso.format_local(time),
|
TimeFormat::ISOFormat(ref iso) => iso.format_local(time),
|
||||||
@ -60,7 +60,7 @@ impl TimeFormat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_zoned(&self, time: Duration, zone: &TimeZone) -> String {
|
pub fn format_zoned(&self, time: SystemTime, zone: &TimeZone) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
TimeFormat::DefaultFormat(ref fmt) => fmt.format_zoned(time, zone),
|
TimeFormat::DefaultFormat(ref fmt) => fmt.format_zoned(time, zone),
|
||||||
TimeFormat::ISOFormat(ref iso) => iso.format_zoned(time, zone),
|
TimeFormat::ISOFormat(ref iso) => iso.format_zoned(time, zone),
|
||||||
@ -146,11 +146,8 @@ impl DefaultFormat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
fn format_local(&self, time: Duration) -> String {
|
fn format_local(&self, time: SystemTime) -> String {
|
||||||
if time.as_nanos() == 0 {
|
let date = LocalDateTime::at(systemtime_epoch(time));
|
||||||
return "-".to_string();
|
|
||||||
}
|
|
||||||
let date = LocalDateTime::at(time.as_secs() as i64);
|
|
||||||
|
|
||||||
if self.is_recent(date) {
|
if self.is_recent(date) {
|
||||||
format!("{:2} {} {:02}:{:02}",
|
format!("{:2} {} {:02}:{:02}",
|
||||||
@ -163,12 +160,8 @@ impl DefaultFormat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
fn format_zoned(&self, time: Duration, zone: &TimeZone) -> String {
|
fn format_zoned(&self, time: SystemTime, zone: &TimeZone) -> String {
|
||||||
if time.as_nanos() == 0 {
|
let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));
|
||||||
return "-".to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
let date = zone.to_zoned(LocalDateTime::at(time.as_secs() as i64));
|
|
||||||
|
|
||||||
if self.is_recent(date) {
|
if self.is_recent(date) {
|
||||||
format!("{:2} {} {:02}:{:02}",
|
format!("{:2} {} {:02}:{:02}",
|
||||||
@ -181,19 +174,45 @@ impl DefaultFormat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn systemtime_epoch(time: SystemTime) -> i64 {
|
||||||
|
time
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.map(|t| t.as_secs() as i64)
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
let diff = e.duration();
|
||||||
|
let mut secs = diff.as_secs();
|
||||||
|
if diff.subsec_nanos() > 0 {
|
||||||
|
secs += 1;
|
||||||
|
}
|
||||||
|
-(secs as i64)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn systemtime_nanos(time: SystemTime) -> u32 {
|
||||||
|
time
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.map(|t| t.subsec_nanos())
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
let nanos = e.duration().subsec_nanos();
|
||||||
|
if nanos > 0 {
|
||||||
|
1_000_000_000 - nanos
|
||||||
|
} else {
|
||||||
|
nanos
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
fn long_local(time: Duration) -> String {
|
fn long_local(time: SystemTime) -> String {
|
||||||
let date = LocalDateTime::at(time.as_secs() as i64);
|
let date = LocalDateTime::at(systemtime_epoch(time));
|
||||||
format!("{:04}-{:02}-{:02} {:02}:{:02}",
|
format!("{:04}-{:02}-{:02} {:02}:{:02}",
|
||||||
date.year(), date.month() as usize, date.day(),
|
date.year(), date.month() as usize, date.day(),
|
||||||
date.hour(), date.minute())
|
date.hour(), date.minute())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
fn long_zoned(time: Duration, zone: &TimeZone) -> String {
|
fn long_zoned(time: SystemTime, zone: &TimeZone) -> String {
|
||||||
let date = zone.to_zoned(LocalDateTime::at(time.as_secs() as i64));
|
let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));
|
||||||
format!("{:04}-{:02}-{:02} {:02}:{:02}",
|
format!("{:04}-{:02}-{:02} {:02}:{:02}",
|
||||||
date.year(), date.month() as usize, date.day(),
|
date.year(), date.month() as usize, date.day(),
|
||||||
date.hour(), date.minute())
|
date.hour(), date.minute())
|
||||||
@ -201,23 +220,23 @@ fn long_zoned(time: Duration, zone: &TimeZone) -> String {
|
|||||||
|
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
fn full_local(time: Duration) -> String {
|
fn full_local(time: SystemTime) -> String {
|
||||||
let date = LocalDateTime::at(time.as_secs() as i64);
|
let date = LocalDateTime::at(systemtime_epoch(time));
|
||||||
format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09}",
|
format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09}",
|
||||||
date.year(), date.month() as usize, date.day(),
|
date.year(), date.month() as usize, date.day(),
|
||||||
date.hour(), date.minute(), date.second(), time.subsec_nanos())
|
date.hour(), date.minute(), date.second(), systemtime_nanos(time))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
fn full_zoned(time: Duration, zone: &TimeZone) -> String {
|
fn full_zoned(time: SystemTime, zone: &TimeZone) -> String {
|
||||||
use datetime::Offset;
|
use datetime::Offset;
|
||||||
|
|
||||||
let local = LocalDateTime::at(time.as_secs() as i64);
|
let local = LocalDateTime::at(systemtime_epoch(time));
|
||||||
let date = zone.to_zoned(local);
|
let date = zone.to_zoned(local);
|
||||||
let offset = Offset::of_seconds(zone.offset(local) as i32).expect("Offset out of range");
|
let offset = Offset::of_seconds(zone.offset(local) as i32).expect("Offset out of range");
|
||||||
format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09} {:+03}{:02}",
|
format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09} {:+03}{:02}",
|
||||||
date.year(), date.month() as usize, date.day(),
|
date.year(), date.month() as usize, date.day(),
|
||||||
date.hour(), date.minute(), date.second(), time.subsec_nanos(),
|
date.hour(), date.minute(), date.second(), systemtime_nanos(time),
|
||||||
offset.hours(), offset.minutes().abs())
|
offset.hours(), offset.minutes().abs())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,8 +263,8 @@ impl ISOFormat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
fn format_local(&self, time: Duration) -> String {
|
fn format_local(&self, time: SystemTime) -> String {
|
||||||
let date = LocalDateTime::at(time.as_secs() as i64);
|
let date = LocalDateTime::at(systemtime_epoch(time));
|
||||||
|
|
||||||
if self.is_recent(date) {
|
if self.is_recent(date) {
|
||||||
format!("{:02}-{:02} {:02}:{:02}",
|
format!("{:02}-{:02} {:02}:{:02}",
|
||||||
@ -259,8 +278,8 @@ impl ISOFormat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
fn format_zoned(&self, time: Duration, zone: &TimeZone) -> String {
|
fn format_zoned(&self, time: SystemTime, zone: &TimeZone) -> String {
|
||||||
let date = zone.to_zoned(LocalDateTime::at(time.as_secs() as i64));
|
let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));
|
||||||
|
|
||||||
if self.is_recent(date) {
|
if self.is_recent(date) {
|
||||||
format!("{:02}-{:02} {:02}:{:02}",
|
format!("{:02}-{:02} {:02}:{:02}",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user