Rails I18n: Days of week - ruby-on-rails

I have a Practice model that is storing start_time, end_time and day.
That information (like the rest of the site) will need to be displayed in 3 different
languages.
Start_time and end_time are both stored as Datetime types in the DB.
Day is not yet implemented, but will be shown as a select box. I have see people suggest an array of constants and storing it as an integer in the DB. While that seems reasonable, I am having trouble imagining that working well with different languages (using either I18n or Globalize2).
What is the cleanest way to implement this so it works well in different languages?

I can't see a good reason to store the days of the week in the database; I'd be surprised if such names will change and we are talking about 7 * 3 strings, that is a small amount of data to handle for your application.
i18n is the way to go. You can browser this repository to find day_names already traslated in different languages.

If you can't store or calculate the day of the week from the start and end DateTime objects, then I would recommend using an ENUM in the database - this causes the data to be stored as an integer - which takes up less space and is easier to index, and the conversion to the string types is done automatically for you so that you can query and insert strings, but the actual database values are integers.
Definitely do not store these values as strings though, it's harder to deal with them and they take up more space.

Related

Storing Date Components Instead of a Date

My app lets people log the movies they see (for example). Each logged movie usually (but not always) has a date and sometimes has a time. It's not unusual to have one but not the other. Occasionally the dates are only a year ("I watched a Dumbo sometime in 1984"), but could realistically be any combination of day/month/year/time.
I am used to modeling dates as date objects in my app and my backend. But is it a viable approach to store each component separately? When I need to reference an actual date from the components (e.g. for sorting the log) this will be built client-side, or perhaps be stored as a derived property sortDate and updated whenever any of the components change.
My reservation is that the information the user is saving is truly a 'moment in time' and I will have to take care of some things myself - for example what time zone are my components stored relative to? This would be captured automatically as part of a real Date object.
The alternative seems to be assuming some sort of 'default' for missing components (e.g. year 0000 if no year, time 00:00 if no time). But those defaults have meaning and I won't be able to distinguish them from 'not provided'.
What are the limitations and/or pitfalls of this approach? Does anyone have experience modeling their dates this way?
If it's of any consequence, my app is for iOS written in Swift and uses a Parse Server backend.
I've successfully used question marks to represent ambiguous and unknown timestamp parts in legal systems. Try to keep in mind that you're really not modeling dates here ('1984' isn't a date); you're modeling facts about dates.
So, if one of your users saw a movie some time in 1984, you might record the value '1984-??-?? ??:??:??' in a text column in a database. Values like this sort sensibly.
See also this answer on dba. Comments on that answer are also good to read.

Rails column type for moment.js formatted date and time

I am building a rails app, where the user picks up a date from a date picker and a time from the time picker. Both the date and time have been formatted using moment js to show the date and time in the following way:
moment().format('LL'); //January 23,2017
moment().format('LTS'); //1:17:54 PM
I read this answer with guidelines about selection of a proper column type.
Is there documentation for the Rails column types?
Ideally, I should be using :date, :time or :timestamp for this. But since the dates are formatted, should I be using :string instead?
Which would be the correct and appropriate column type to use in this situation?
If you want to store a time reference in your database you should use one of the types the database offers you. I'll explain this using MySQL (which is the one I have used the most) but the explanation should be similar in other database servers.
If you use a timestamp column you will be using just 4 bytes of storage, which is always a good new since it makes smaller indexes, uses less memory in temporal tables during the internal database operations and so on. However, timestamp has a smaller range than datetime so you will only be able to store values from year 1970 up to year 2038 more or less
If you use datetime you will be able to store a wider range (from year 1001 to year 9999) with the same precision (second). The bad consequence is that a higher range needs more memory, making it a bit slower.
There are some other differences between these two column types that don't fit in this answer, but you should keep an eye on before deciding.
If you use varchar, which is the default column type for text attributes in Ruby on Rails, you will be forced to convert from text to datetime and vice-versa every time you need to use that field. In addition, ordering or filtering on that column will be very inefficient because the database will need to convert all strings into dates before filtering or sorting, making it impossible to use indexes on that column.
If you need sub-second precision, you can use bigint to meet your requirements, as MySQL does not provide a date specific type for this purpose
In general, I recommend using timestamp if your application requirements fit the timestamp limitation. Otherwise, use datetime, but I strongly discourage you to use varchar for this purpose.
EDIT: Formatting
The way you store dates in database is completely different from the way you display it to the user. You can create a DateTime object using DateTime.new(year, month, day, hour, minute, second) and assign that object to your model. By the time you save it into database, ActiveRecord will be in charge of converting the DateTime object into the appropiate database format.
In order to display a value that is already stored in database in a specific format (in a view, API response, etc.) you can hava a look at other posts like this one.
You can have a timestamp column in your database, and then parse the request to a ruby datetime object like this:
d = Time.parse(params[:date])
t = Time.new(params[:time])
dt = DateTime.new(d.year, d.month, d.day, t.hour, t.min, t.sec, t.zone)
#now simply use dt to your datetime column
On Postgres you can save a ruby DateTime object straight into a postgres timestamp field, e.g
User.first.update_attribute('updated_at', dt )
Another option is to concatenate your date and time strings into one and then u can do a one-liner:
User.last.update_attribute('created_at', Time.parse('January 23,2017 1:17:54 PM'))
I'm pretty sure this will work on MySQL datetime or timestamp as well.
Credit to david grayson Ruby: combine Date and Time objects into a DateTime

Lua Date Format and Comparison

How do you compare dates with lua? What is the best string format for dates? Should I store dates in epoch? I am looking for performance ...
Is the best way os.difftime?
You are asking several things, so here are my answers:
Should I store dates in epoch?
In general yes, the best way to store the dates is by using epochs, as returned by os.time
How do you compare dates with lua?
It depends on how you want to "compare" them.
If you just want to know which one is newer/older, then the easiest fastest thing is storing them as "epochs" and then doing date1 < date2; since both dates are just numbers, this is both performant and clean.
If you want to know how many months/days/years have passed between two given dates, that's a bit more complex. You will need a code similar to this:
diff = os.date("*t", os.difftime(date1, date2))
On that example, the returned diff is a table similar to {year=1, month=5, day=1, hour=2, min=3, sec=40 ...}
I am looking for performance ...
If you are using os.date() too often to transform epochs into dates (for example, for printing) then you might want to "cache" the year, month, etc information in a table, so you don't have to call it again and again. But do this only if you experience a bad performance; don't pre-optimize.
What is the best string format for dates?
That completely depends on how you want to use them. For example, if your app interacts with another service that expects a certain date format, it makes sense to use that format in all your app.
If you have no particular need to use a format, then one candidate is (%x):
os.date("%x", date) -- 09/16/1998 (for example)
The string that gives you depends on the computer's locale. This might or might not be desirable.
If you want the representation to be the same across all computers, independently of their locale, you might want to try a standard format, like ISO 8601:
os.date("%Y-%m-%d", date) -- returns "1998-09-16" in all computers
This format has lots of advantages; the most obvious one is that dates sorted out alphabetically are also sorted out chronologically. But the most important one is that a lot of software out there is prepared to read/use it.
You can find more information about dates in Programming in Lua, Section 22.1 - Date and Time and in the lua-users wiki.

Scoping out how to handle UGC dates/times

I'm scoping out how to handle user-generated dates with rails and was hoping to get some thoughts on the best way to handle them. Ultimately I want to display dates/times provided by the user in HTML, and I also want to sort by the dates (ascending and descending, depending). My initial thought was to create the db as time: string and date:string and then convert these strings to datetime values. Is there a better way to go about this? I'm using RoR 3.1.
Any thoughts and ideas would be greatly appreciated so I don't start down the wrong path only to realize at a later date.
Yes, there is a better way to go about it. ActiveRecord supports the following types for times:
datetime
timestamp
time
date
So pick the type that matches your intent (time for time of day, date for a date, ...) and then let AR do its job and deal with the details. Then you'll get the right data in the database and the right objects in your Ruby; once you have the right objects in your Ruby everything will sort and compare and what not properly.

How would you build this daily class schedule?

What I want to do is very simple but I'm trying to find the best or most elegant way to do this. The Rails application I'm building now will have a schedule of daily classes. For each class the fields relevant to this question are:
Day of the week
Starting time
Ending time
A single entry could be something such as:
day of week: Wednesday
starting time: 10:00 am
ending time: Noon
Also I must mention that it's a bi-lingual Rails 2.2 app and I'm using the native i18n Rails feature. I actually have several questions.
Regarding the day of the week, should I create an extra table with list of days, or is there a built-in way to create that list on the fly? Keep in mind these days of the week will have to be rendered in English or Spanish in the schedule view depending on the locale variable.
While querying the schedule I will need to group and order the results by weekday, from Monday to Sunday, and of course order the classes within each day by starting time.
Regarding the starting time and ending time of each class would you use datetime fields or integer fields? If the latter how would you implement this exactly?
Looking forward to read the different suggestions you guys will come up with.
I would just store the day of the week as an integer. 0 => Monday ... 6 => Sunday (or any way you want. ie. 0 => Sunday). Then store the start time and end time as Time.
That would make grouping really easy. All you would have to do is sort by the day of the week and the start time.
You can display this in multiple ways, but here is what I would do.
Have functions like: #sunday_classes = DailyClass.find_sunday_classes that returns all the classes for Sunday sorted by start time. Then repeat for each day.
def find_sunday_classes
find_by_day_of_week(1, :order -> 'start_time')
end
Note: find_by probably should have id at the end but that's just preference in how you want to name the column.
If you want the full week then call all seven from the controller and loop trough them in the view. You could even create detail pages for each day.
Translation is the only tricky part. You can create a helper function that takes an integer and returns the text for the appropriate day of the week based on local.
That's very basic. Nothing complicated.
If your data is a Time then I would store that as a Time - otherwise you will always have to convert it out of the database when you do date and time related operations on it. The day is redundant data, as it will be part of the time object.
This should mean that you don't need to store a list of days.
If t is a time then
t.strftime('%A')
will always give you the day as a string in English. This could then be translated by i18n as required.
So you only need to store starting time and ending time, or starting time and duration. Both should be equivalent. I would be tempted to store ending time myself, in case you need to do data manipulations on ending times, which therefore won't have to be calculated.
I think most of the rest of what you describe should also fall out of storing time data as instances of Time.
Ordering by week day and time will just be a matter of ordering by your time column. i.e.
daily_class.find(:all, :conditions => ['whatever'], :order => :starting_time)
Grouping by day is a little more tricky. However this is an excellent post on how to group by week. Grouping by day will be analogous.
If you are dealing with non-trivial volumes of data, it may be better to do it in the database, with a find_by_sql and that may depend on your database's time and date functionality, but again storing the data as a Time will also help you here. For example in Postgresql (which I use), getting the week of a class is
date_trunc('week', starting_time)
which you can use in a Group By clause, or as a value to use in some loop logic in rails.
Re days-of-week, if you need to have e.g. classes that meet 09:00-10:00 on MWF, then you could either use a separate table for days a class meets (keyed by both class ID and DOW) or be evil (i.e. non-normalized) and keep the equivalent of an array of DOW in each class. The classic argument is this:
The separate table can be indexed in a way to support either class-oriented or DOW-oriented selects, but takes a bit more glue to put the entire picture together for a class.
The array-of-DOW is simpler to visualize for beginning programmers and slightly simpler to code about, but means that reasoning about DOW requires looking at all classes.
If this is only for your personal class schedule, do what gets you the value you're looking for, and live with the consequences; if you're trying to build a real system for multiple users, I'd go with a separate table. All those normalization rules are there for a reason.
As far as (human-readable) DOW names, that's a presentation-layer issue, and shouldn't be in the core concept of DOW. (Suppose you decided to move to Montreal, and needed French? That should be another "face" and not a change to the core implementation.)
As for starting/ending times, again the issue is your requirements. If all classes begin and end at hour (x:00) boundaries, you could certainly use 0..23 as the hours of the day. But then your life would be miserable as soon as you had to accommodate that 45-minute seminar. As the old commercial said, "Pay me now or pay me later."
One approach would be to define your own ClassTime concept and partition all reasoning about times to that class. It could start with a simplistic representation (integral hours 0..23, or integral minutes after midnight 0..1439) and then "grow" as needed.

Resources