2012-12-05 19 views
5

Sto cercando un modo valido per convalidare e quindi confrontare una stringa di data passata da un servizio REST.Confronto di stringhe di date con date effettive in Scala

Se ottengo il 2012-12-25 (anno-mese-giorno) passato come stringa, quale sarebbe un modo elegante per confermare che è una data valida, e quindi per dire che la data è in futuro o in il passato?

Per lavorare con le date in Scala, è possibile ovviamente utilizzare le librerie Java esistenti. Ma lavorare con le date in Java è sempre stato come servire il lato oscuro, quindi non voglio trascinare troppo di quell'eredità nel mio attuale stile di programmazione. Guardando lo Scala Dates example on langref.org, sento che tornerò a programmare Java se seguirò questo stile di programmazione.

+2

Non sono un esperto di Scala con qualsiasi mezzo, ma forse il [Joda Time wrapper con il nome di 'Scala Time'] (https://github.com/jorgeortiz85/scala-time) potrebbe funzionare per voi. .. –

risposta

5

JodaTime va bene, va bene, va bene, non preoccuparti del lato oscuro, non esiste (o almeno non in questa particolare libreria Java).

// "20121205".to_date 
class String2Date(ymd: String) { 
    def to_date = { 
    try{ Some(ymdFormat.parseDateTime(ymd)) } 
    catch { case e:Exception => None } 
    } 
    val ymdFormat = org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd") 
} 
@inline implicit final def string2Date(ymd: String) = new String2Date(ymd) 

def dater(ymd: String) = { 
    val other = new JodaTime 
    ymd.to_date map{d=> 
    if(d.isBefore other) ... 
    else ... 
    } getOrElse("bad date format") 
} 

Può fare praticamente qualsiasi cosa data/ora relativa a JodaTime; è assurdo quanto sia buona questa libreria: inequivocabile il pollice in su.

+0

Sembra una buona opzione, grazie. Utilizzeresti normalmente il progetto scala-time (https://github.com/jorgeortiz85/scala-time)? – Jack

+0

no, non ho trovato bisogno di ScalaTime, JodaTime as is è abbastanza conciso; Ad esempio, i miglioramenti di DSL su cui ScalaTime si concentra non sono essenziali per le mie esigenze.JodaTime funziona perfettamente con Scala, Java interopace in azione ;-) – virtualeyes

+0

+1 Per JodaTime su Java Date libraries * yuck * – fresskoma

3

È possibile farlo utilizzando la libreria Java SimpleDateFormat di serie:

def parseDate(value: String) = { 
    try { 
    Some(new SimpleDateFormat("yyyy-MM-dd").parse(value)) 
    } catch { 
    case e: Exception => None 
    } 
} 

e poi utilizzato in questo modo:

parseDate("2012-125") // None 
parseDate("2012-12-05") // Some(Wed Dec 05 00:00:00 EST 2012) 

Poi si può avere una funzione per testare le date future:

def isFuture(value: Date) = value.after(new Date) 
+0

+1 Ben spiegato, grazie – Jack

1

Anche se ci sono alcuni svantaggi nell'usare le librerie di date java come la mancanza di sicurezza hread (Why is Java's SimpleDateFormat not thread-safe?) e di un difficile da usare API, è possibile utilizzare impliciti per rendere le cose un po 'più gradevole al palato:

implicit def stringToDate(date: String) = new { 
    def parse(implicit format: String) = parse0(date)(format) 
    private def parse0(date: String)(implicit format: String) = { 
    val sdf = new SimpleDateFormat(format) 
    sdf.setLenient(false) 
    sdf.parse(date) 
    } 
    def isValid(implicit format: String) = try { parse0(date)(format); true } catch { case _ => false } 
    def beforeNow(implicit format: String) = parse0(date)(format) before new Date() 
    def afterNow(implicit format: String) = parse0(date)(format) after new Date() 
} 

allora si potrebbe utilizzare in questo modo:

implicit val format = "yyyy-MM-dd" 
"2012-12-02" isValid // true 
"2012-12-02" beforeNow // ? 
"2012-12-25" afterNow // ? 

Oppure, si potrebbe utilizzare scala-time:

import org.joda.time.format.ISODateTimeFormat._ 
import org.joda.time.DateTime 
for(date <- date.parseOption("2012-12-02")) yield date < new DateTime // Option(?) 

Con questo approccio, si ottiene un'interfaccia Scala-friendly, e non c'è bisogno di creare e analizzare un nuovo oggetto SimpleDateFormat o conservarlo in a hread local per evitare problemi di threading.

1

Se si desidera davvero evitare l'utilizzo di qualsiasi libreria di data e ora, è possibile utilizzare un'espressione regolare appropriata (come quella in questa risposta: https://stackoverflow.com/a/7221570/227019) per verificare che la stringa sia effettivamente una data ISO 8601 valida, quindi utilizzare il fatto che tali date possono essere confrontate lessicograficamente per determinare il loro ordinamento temporale (è sufficiente formattare la data corrente nello stesso formato e confrontarla con l'altra data utilizzando il confronto di stringhe regolari).