im burning my brains trying to make a function that gives me the ammount of days between todays date and a given date.
possible today function:
today = fmap (formatTime defaultTimeLocale "%Y-%m-%d") getCurrentTime
and thought using diffDays, but wont be able to make it work with a ::Day date
any ideas?
Your formatTime version returns a string, but you want a Day (which looks like your string when you inspect it, but is a different type entirely). Here's one way to write a today function, using utctDay to get a Day out of a UTCTime:
import Data.Time.Calendar
import Data.Time.Clock
today :: IO Day
today = fmap utctDay getCurrentTime
And here's a days-from-today function (which I gave the shorter name daysAway) that uses it:
daysAway :: Day -> IO Integer
daysAway day = fmap (diffDays day) today
If you're always specifying the target as a calendar date, you can do that easily enough:
daysToDate :: Integer -> Int -> Int -> IO Integer
daysToDate year month day = daysAway $ fromGregorian year month day
Given a shorthand function for a commonly-needed relative day:
tomorrow :: IO Day
tomorrow = fmap (addDays 1) today
We can demonstrate the correctness of Annie's Thesis:
ghci> tomorrow >>= daysAway
1
Related
I want to get the current time, and format it in the following way:
yyyy-MM-dd'T'HH:mm:ss.SSSZ
(where SSS is the milliseconds and Z the time zone)
the code so far I have it as follows:
formatted_date() ->
{{Y,M,D},{H,Min,S}} = erlang:localtime(),
{Ms, _, _} = os:timestamp(),
{Days, {Hours, _,_}} = calendar:time_difference(erlang:universaltime(), erlang:localtime()),
Difference = 24*Days + Hours,
Tz = [case Difference < 0 of
true ->
$-;
false ->
$+
end | io_lib:format("~2..0B00",[Difference])],
io_lib:format("[~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0B.~3..0B ~5.s]",
[Y, M, D, H, Min, S, Ms, Tz]).
The fact is that it always returns the same Ms, therefore, I think that I am not doing it well, and in other questions I only see how to obtain the total time in milliseconds, but not how to format it in this way.
Thank you.
The easiest way is to use the library function calendar:system_time_to_rfc3339/2 - it seems to fulfil all your requirements.
> calendar:system_time_to_rfc3339(os:system_time(millisecond), [{unit, millisecond}]).
"2021-03-03T18:42:08.497+05:30"
This function was added in Erlang/OTP 21.0, which was released in June 2018.
The reason your code always gets the same value for Ms is that the first value in the tuple returned by os:timestamp/0 is megaseconds, not milliseconds; the three values are megaseconds, seconds and microseconds. This comes from a time when Erlang did not support large integers, so splitting up the timestamp was necessary. These days you can just call os:system_time/1 or a number of other functions, depending on what kind of time you need, and get the result in a single integer.
I have a 6 digit value from which i have to get the date in scala. For eg if the value is - 119003 then the output should be
1=20 century
19=2019 year
003= january 3
The output should be 2019/01/03
I have tried ti split the value first and then get the date. But i am not sure how to proceed as i am new to scala
I think you'll have to do the century calculations manually. After that you can let the java.time library do all the rest.
import java.time.LocalDate
import java.time.format.DateTimeFormatter
val in = "119003"
val cent = in.head.asDigit + 19
val res = LocalDate.parse(cent+in.tail, DateTimeFormatter.ofPattern("yyyyDDD"))
.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"))
//res: String = 2019/01/03
The Date class of Java 1.0 used 1900-based years, so 119 would mean 2019, for example. This use was deprecated already in Java 1.1 more than 20 years ago, so it’s surprising to see it survive into Scala.
When you say 6 digit value, I take it to be a number (not a string).
The answer by jwvh is correct. My variant would be like (sorry about the Java code, please translate yourself):
int value = 119003;
int year1900based = value / 1000;
int dayOfYear = value % 1000;
LocalDate date = LocalDate.ofYearDay(year1900based + 1900, dayOfYear);
System.out.println(date);
2019-01-03
If you’ve got a string, I would slice it into two parts only, 119 and 003 (not three parts as in your comment). Parse each into an int and proceed as above.
If you need 2019/01/03 format in your output, use a DateTimeFormatter for that. Inside your program, do keep the LocalDate, not a String.
How to get following DateTime in Erlang?
Fri Jul 13 19:12:59 IST 2018
TL; DR
Use the exceptional qdate for all your date/time formatting, converting, and timezone handling. Look at the Demonstration section in particular to get the gist, and adjust to your needs.
Erlang's date handling, in my opinion, is convoluted and lacking in the major functionality that's needed for proper date handling. It's getting better, but not quite there. Moreover, timezone handling is primitive at best.
qdate's functions will take (almost) any date format and convert to any date format, while using either an implicit timezone (setting the timezone on a per-process basis), or by setting a specific timezone.
In any case, if you go custom, you will end up with something similar to this:
1> {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_datetime(erlang:now()).
{{2018,7,13},{14,39,45}}
2> lists:flatten(io_lib:format("~4..0w-~2..0w-~2..0wT~2..0w:~2..0w:~2..0w",[Year,Month,Day,Hour,Minute,Second])).
"2018-07-13T14:39:45"
...not good ;)
Those are my two cents. Cheers!
I found the solution.
A = calendar:universal_time().
qdate:to_string(<<"D M j G:i:s T Y">> , <<"IST">>, A).
You can use http://uk3.php.net/manual/en/function.date.php for different formatting. Advisable to use only if you have to support legacy system because this function call use seems expensive.
date_time() ->
{{Year, Month, Day},{ Hour, Minute, Second}} = calendar:local_time(),
DayOfWeek = calendar:day_of_the_week({Year, Month, Day}),
DayName = day_check(DayOfWeek),
MonthName = month_check(Month),
lists:flatten(io_lib:format("~3..0s ~3..0s ~2..0w ~2..0w:~2..0w:~2..0w IST ~4..0w", [DayName, MonthName, Day, Hour, Minute, Second, Year])).
day_check(1) -> 'Mon';
day_check(2) -> 'Tue';
day_check(3) -> 'Wed';
day_check(4) -> 'Thu';
day_check(5) -> 'Fri';
day_check(6) -> 'Sat';
day_check(7) -> 'Sun'.
month_check(1) -> 'Jan';
month_check(2) -> 'Feb';
month_check(3) -> 'Mar';
month_check(4) -> 'Apr';
month_check(5) -> 'May';
month_check(6) -> 'Jun';
month_check(7) -> 'Jul';
month_check(8) -> 'Aug';
month_check(9) -> 'Sep';
month_check(10) -> 'Oct';
month_check(11) -> 'Nov';
month_check(12) -> 'Dec'.
I am new to haskell and wanted to approach learngin by attempting bits of a real world application. One of the components is being able to parse dates in ISO formatted strings into it's components. This Stack Overflow post helped me get started, but it isn't enough and I am quite confused.
I have the following code:
import System.Locale
import Data.Time
import Data.Time.Format
data IsoDate = IsoDate {
year :: Int
, month :: Int
, day :: Int
} deriving (Show)
parseIsoDate :: String -> IsoDate
parseIsoDate dateString =
IsoDate year month day
where
timeFromString = readTime defaultTimeLocale "%Y %m %d" dateString :: UTCTime
year = 2013
month = 10
day = 31
Which is fine and dandy for Halloween 2013. I have attmepted to rewrite year as:
year = formatTime defaultTimeLocale "%y" timeFromString
which I knew would fail (can't construct my IsoDate type with a String). And then attempted to read the string into an Int.
year = read (formatTime defaultTimeLocale "%y" timeFromString)
with the following response:
parseIsoDate "2012-12-23"
IsoDate {year = *** Exception: readsTime: bad input "2012-12-23"
There were a couple other attemps at getting this converted - but what I posted was the most rational attempt, o I am not going to post the other attempts.
I wanted to figure out how to work with my current code (as I am trying to learn the constructs), in addition (since date parsing is essential) I would like to know the better way (perhaps the most idiomatic) to handle this in Haskell.
I think the stuff you need to do is
parseIsoDate :: String -> Maybe IsoDate
because not every String you supply will be a valid date. Implementing it you already got most of the ingredients right, but I don't think yo uwant to parse a UTCTime but a Day which can be converted into your data-structure.
import Data.Time
data IsoDate = ...
parseIsoDate :: String -> Maybe IsoDate
parseIsoDate str = do julianDay <- parse str
let (y, m, d) = toGregorian julianDay
return $ IsoDate (fromIntegral y) m d
where parse:: String -> Maybe Day
parse = parseTimeM True defaultTimeLocale "%F"
now a bit explaining and advice:
I would change the datatype IsoDate to using Integer for years - as they are possibly big (at least bigger than Int - just look at the age of our universe). this is also the choice of the result of toGregorian which converts a Day -> (Integer, Int, Int), if not you have to convert the Integer produced by it to an Int with the help of fromIntegral as you see in my example.
the syntax I use is called do-syntax for Maybe, which is a handy thing in the first line I extract a value inside the monad and bind it to a name - julianDay.
Then I transform the value to a Gregorian Day.
And then return it into the Maybe again. If the first step fails and produces a Nothing, i.e. the String is just gobbledygook, then none of the other operations are done and your program finishes without doing any work (that's the power of lazy evaluation).
update
If you are using the RecordWildCards extension, and the fact that maybe is a Functor you can do the following
{-# LANGUAGE Record
module MyLib
import Data.Time
data IsoDate = IsoDate { year :: Integer
, month :: Int
, day :: Int}
deriving (Show)
parseIsoDate :: String -> Maybe IsoDate
parseIsoDate str = do (year, month, day) <- toGregorian <$> parse str
return IsoDate{..}
where parse:: String -> Maybe Day
parse = parseTimeM True defaultTimeLocale "%F"
Here is one answer:
data IsoDate = IsoDate {
year :: Int
, month :: Int
, day :: Int
} deriving (Show)
parseIsoDate :: String -> IsoDate
parseIsoDate dateString =
IsoDate year month day
where
timeFromString = readTime defaultTimeLocale "%Y %m %d" dateString :: UTCTime
year = read (formatTime defaultTimeLocale "%0Y" timeFromString) :: Int
month = read (formatTime defaultTimeLocale "%m" timeFromString) :: Int
day = read (formatTime defaultTimeLocale "%d" timeFromString) :: Int
Which refactors to:
data DatePart = Year | Month | Day deriving(Enum, Show)
datePart :: DatePart -> UTCTime -> Int
datePart Year utcTime = read (formatTime defaultTimeLocale "%0Y" utcTime)
datePart Month utcTime = read (formatTime defaultTimeLocale "%m" utcTime)
datePart Day utcTime = read (formatTime defaultTimeLocale "%d" utcTime)
parseIsoDate :: String -> IsoDate
parseIsoDate dateString =
IsoDate year month day
where
timeFromString = readTime defaultTimeLocale "%Y %m %d" dateString :: UTCTime
year = datePart Year timeFromString
month = datePart Month timeFromString
day = datePart Day timeFromString
in usage
parseIsoDate "2012 12 02"
THat data isn't in ISO format, still working to get it to read "2012-12-01". Also still looking for the preferred way of getting this to work within the language.
update the dashes are trivial change "%Y %m %d" to "%Y-%m-%d" I thought I had tried that eariler, but it must have been with other code in error.
If I've got a time_t value from gettimeofday() or compatible in a Unix environment (e.g., Linux, BSD), is there a compact algorithm available that would be able to tell me the corresponding week number within the month?
Ideally the return value would work in similar to the way %W behaves in strftime() , except giving the week within the month rather than the week within the year.
I think Java has a W formatting token that does something more or less like what I'm asking.
[Everything below written after answers were posted by David Nehme, Branan, and Sparr.]
I realized that to return this result in a similar way to %W, we want to count the number of Mondays that have occurred in the month so far. If that number is zero, then 0 should be returned.
Thanks to David Nehme and Branan in particular for their solutions which started things on the right track. The bit of code returning [using Branan's variable names] ((ts->mday - 1) / 7) tells the number of complete weeks that have occurred before the current day.
However, if we're counting the number of Mondays that have occurred so far, then we want to count the number of integral weeks, including today, then consider if the fractional week left over also contains any Mondays.
To figure out whether the fractional week left after taking out the whole weeks contains a Monday, we need to consider ts->mday % 7 and compare it to the day of the week, ts->wday. This is easy to see if you write out the combinations, but if we insure the day is not Sunday (wday > 0), then anytime ts->wday <= (ts->mday % 7) we need to increment the count of Mondays by 1. This comes from considering the number of days since the start of the month, and whether, based on the current day of the week within the the first fractional week, the fractional week contains a Monday.
So I would rewrite Branan's return statement as follows:
return (ts->tm_mday / 7) + ((ts->tm_wday > 0) && (ts->tm_wday <= (ts->tm_mday % 7)));
If you define the first week to be days 1-7 of the month, the second week days 8-14, ... then the following code will work.
int week_of_month( const time_t *my_time)
{
struct tm *timeinfo;
timeinfo =localtime(my_time);
return 1 + (timeinfo->tm_mday-1) / 7;
}
Assuming your first week is week 1:
int getWeekOfMonth()
{
time_t my_time;
struct tm *ts;
my_time = time(NULL);
ts = localtime(&my_time);
return ((ts->tm_mday -1) / 7) + 1;
}
For 0-index, drop the +1 in the return statement.
Consider this pseudo-code, since I am writing it in mostly C syntax but pretending I can borrow functionality from other languages (string->int assignment, string->time conversion). Adapt or expand for your language of choice.
int week_num_in_month(time_t timestamp) {
int first_weekday_of_month, day_of_month;
day_of_month = strftime(timestamp,"%d");
first_weekday_of_month = strftime(timefstr(strftime(timestamp,"%d/%m/01")),"%w");
return (day_of_month + first_weekday_of_month - 1 ) / 7 + 1;
}
Obviously I am assuming that you want to handle weeks of the month the way the standard time functions handle weeks of the year, as opposed to just days 1-7, 8-13, etc.