Storing Time Stamp as Number Mongoid - ruby-on-rails

I'm new to Mongoid. In my model file, I've created a field with data type BigDecimal. I want to store time stamp in it. Below is the model that I'm using:
class Test
include Mongoid::Document
field :time_stamp, type: BigDecimal
end
And Below is the code that I'm using to create a document:
aTime = "Wed Apr 24 09:48:38 +0000 2013"
timest = aTime.to_time.to_i
Test.create({time_stamp: timest})
I see that the time_stamp is stored as String in the database. Can anybody direct me to store the timestamp as number in DB so that I could perform some operations on it. Thanks in advance.

According to this answer, the numeric types supported by MongoDB are:
MongoDB stores data in a binary format called BSON which supports these numeric data types:
int32 - 4 bytes (32-bit signed integer)
int64 - 8 bytes (64-bit signed integer)
double - 8 bytes (64-bit IEEE 754 floating point)
Reinforced by this statement in the Mongoid documentation:
Types that are not supported as dynamic attributes since they cannot be cast are:
BigDecimal
Date
DateTime
Range
I don't know about the things you want to with the field, but if you really want it stored as a number, you have to use a different numeric type that is supported by the MongoDB (BSON), probably Float or Integer.

Related

Dart: DateTime.parse() not including microseconds

See the following code:
void main()
{
String test = '2017-10-11T12:03:46.351363-04:00';
DateTime testDate = DateTime.parse(test);
print(testDate.microsecond);
print(testDate.toString());
}
When running this code I lose the microseconds in the string that I parse. Why is this and is there anyway to solve this?
The Dart docs say that the parse method supports microseconds.
'2017-10-11T12:03:46.351363-04:00' is not a format Dart's DateTime can handle.
DateTime only supports Z for GMT or no Z for local time.
Just print the value from a created DateTime to see what format it can parse.
print(DateTime.now());
print(DateTime.now().toUtc())
DateTime has also 2 constructors fromMicrosecondsSinceEpoch and fromMillisecondsSinceEpoch to create an instance from an integer value.
There's an issue here
https://github.com/dart-lang/co19/issues/17
As the test show it only 6 decimal places
https://github.com/dart-lang/co19/commit/8465825f60c9580d82ae01ffc040f3b589aaf667#diff-02c526d1dcb5aa2dcdab3500c14ede87R40
You can parse format 2018-12-11T12:00:32.304272Z
but cannot parse 2018-12-11T12:00:32.304272001Z
I found an issue for dart-lang/sdk.
https://github.com/dart-lang/sdk/issues/44876
The web Date object doesn't support microseconds. It's implemented
using the JavaScript Date object which only supports millisecond
precision. So, working as well as possible.

How to model decimal type in RAML

I am modelling a REST API using RAML. The response body of an endpoint (JSON format) is a financial transactions list. Each transactions contains an amount of money: currency and numeric value. The following is the snippet of my RAML file, please note the property amount in the Transaction type:
# %RAML 1.0
title: Trading details API
version: v1
mediaType: application/json
baseUri: http://my.host.io/api/trading/v1/
types:
Transactions:
type: Transaction[]
minItems: 1
Transaction:
type: object
properties:
refNum:
type: string
amount:
type: ????
currency:
type: string
minLength: 2
maxLength: 3
/trades
get:
description: Get details for a given trade
queryParameters:
userId:
type: integer
required: true
responses:
200:
body:
application/json:
type: Transactions
Unfortunately RAML has no Built-in decimal type, and the other numeric types (integer, float or double) are not suitable for this scope, mainly because I need to specify the number of digits after the . .
So question is: in RAML how do I correctly model the type amount?
I need to provide an exact definition of the type for each response body values, because this file will be the contract between the backend and frontend (developed by 2 different teams).
Any helps is welcomed.
Please note that I made some research on SO, and the closest question to mine is: How to define money amounts in an API
. But it is not related to RAML modelling, and the answers are not helping to me.
RAML has a similar construct to the one in JSON Schema. You'll want to use type: number in combination with multipleOf to describe decimal precision.
#%RAML 1.0 DataType
type: number
multipleOf: 0.01
After months I come back to share my experience.
The way I worked around it was by using the type string and a pattern. I am aware of the many concerns around changing the data type from number to string, but this approach is elegant, robust, flexible and still simple to test and understand.
The API consumers are forced to format the amount in the correct way and the messages coming in and out of the API are consistent, consistency cannot be guaranteed by using multiplyOf 0.0001 (where 25 and 25.0000 are both accepted).
I reused over and over this solution with great results. Therefore I am sharing this with the community.
Solution:
[...]
amount:
type: string
pattern: "^(([1-9][0-9]*)|[0])[.]([0-9]{4})$"
currency:
type: string
...
The pattern accepts 4 digits on the decimal part, forces to use a . and the amount cannot starts with 0, with the exception of 0.xxxx family of numbers.
The following is an examples list of accepted numbers:
1.0000
54.0000
23456.1234
1.9800
0.0000
0.0001
Instead the following is an example list of rejected:
0123.3453
12.12
1.1
000
01.0000
1.0
1.00
4.000
Moreover, you can specify the max number of digits on the left side (in this example 10):
pattern: "^(([1-9][0-9]{0,9})|[0])[.]([0-9]{4})$"
Example of accepted numbers:
1234567890.1234
3.5555
0.1234
Example of rejected numbers:
12345678901.1234
123456789012.1234

Define Money Fomat in Laravel

I am trying to save money format in laravel 5.1.
Here is table price define:
$table->decimal(price,6,2);
For instance ; when 1.000,50 Turkish Liras saving to MySQL this format 1.00
How can solve this issue?
You can try defining your price like this
$table->decimal('price',9,3);
Where,
9 is the precision, ie 1234567.89 has a precision of 9
3 is the number of decimal places, ie 123456.789 has a scale of 3
In other words, if we use less decimal-places than 3, we can use remaining for real-number places.
You can refer to this link for about precision and scale of database
How do I interpret precision and scale of a number in a database?
I would suggest not using a float value to store currency as decimals, since floats don't act exactly as you would expect them to, due to the way they are stored in the system.
You would be much better off storing the value in "kuruş" (the subunit of Turkish Lira), as it will be much, much easier in the long run.
In other words, storing the lowest unit you think will be ever required, like storing Centi-meters instead of Meters (Centi is originally Greekish name for "0.01" number).
Secondly, if you're using Eloquent you can use mutators/accessors on the Model e.g.
public function getPriceAttribute($price)
{
return $price / 100;
}
public function setPriceAttribute($price)
{
$this->attributes['price'] = $price * 100;
}
That way you don't have to manually convert the price.
Update
If you're using Laravel 9 or above, you can use the new Attribute syntax instead:
use Illuminate\Database\Eloquent\Casts\Attribute;
protected function price(): Attribute
{
return Attribute::make(
get: fn ($price) => $price / 100,
set: fn ($price) => $price * 100,
);
}
Illuminate blueprints do not support money columns. AFAIK, the money column type itself is only supported in a couple of DBMSes.
What you can do is issue an ALTER TABLE statement to the database after the initial CREATE statement:
Schema::create('my_table', function(Blueprint $table) {
$table->decimal('my_money_column', 999, 2);
// ... the rest of the column definitions
});
DB::statement("
ALTER TABLE my_table ALTER COLUMN my_money_column
SET DATA TYPE MONEY;
");
Beware, though, as this will (probably) break cross-DBMS compatibility of your migration scripts.

Delphi tclientdataset .cds datetime binary timeformat unpack

I am trying to parse .cds delphi database file. Simple int values and strings are easy to parse. But the only one i cannot understand is a DateTime format.
I found 6 bytes that affecting DateTime Value
I am using python and the following code:
data = '\x00\x00' + '\xBC\xCE\x6F\xEC\xE7\xCC'
data_long = struct.unpack('Q', data)[0]
But struct.unpack doesnt have 6 byte type values, so i added \x00 \x00 to make 8 byte long value ('Q' option)
Here is small sample .cds file with one row https://yadi.sk/d/PkZKy50YgCmqE
DateTimeIssl value = "16.04.2015 9:25:47"
I found 6 hex values but cant unpack it properly.
Can anyone tell me how to read it, or maybe give me a link to some documentation about .cds file structure?
Update:
OK! Thanks to Deltics for guide me how to read TDateTime. I found some test values on internet and i wrote decode function that converts it to Python datetime object.
data = '\x2E\xD8\x82\x2D\xCE\x47\xE3\x40'
data_double = struct.unpack('d', data)[0]
double_split = str(data_double).split('.')
SECONDS_IN_DAY = 60*60*24
time_from_starting_date = timedelta(days=int(double_split[0]), seconds=int(SECONDS_IN_DAY * (float(double_split[1]) * pow(0.1, len(double_split[1])))))
starting_date = datetime(1899, 12, 30)
result_date = starting_date + time_from_starting_date
print time_from_starting_date
print result_date
For 2E D8 82 2D CE 47 E3 40 it will be 08.02.2008 10:38:00.
Works fine.
But i still cannot found valid 8-bytes for field DateTimeIssl in file that i've linked above. Maybe there a different datetime format?
A Delphi date/time (TDateTime) is a Double precision floating point. This is an 8-byte value. You should not need to add any packing or null bytes. If you are having to do this then you have not identified the double value correctly in the file.
Looking at the sample CDS you linked to, each value that could sensibly be interpreted as a date/time (e.g. DateRoshd, DateTimeIssl) is followed by 8 bytes of data.
After reading the double value, the whole number part of this value indicates the date as the number of days since 30 Dec 1899. The decimal part is the time of day on that date.
e.g.
1.0 = 31 Dec 1899, 00:00 (midnight)
2.5 = 1 Jan 1900, 12:00 (midday)
More information on the Delphi TDateTime data type can be found here.
Responding to myself. Maybe for someone it will be useful.
In binary format, TClientDataSet DateTime contains INTEGER value of milliseconds since 02.01.0001, but stores as a 8-byte DOUBLE
So you have to read 8-bytes, unpack it as a double, then convert value to integer. Here is Python code that worked for me:
data = '\x00\xBC\xCE\x6F\xEC\xE7\xCC\x42' # Time: 2015-04-16 09:25:47
data_double = struct.unpack('d', data)[0]
time_from_starting_date = timedelta(days=-2, milliseconds=long(data_double))
starting_date = datetime(0001, 01, 02)
result_date = starting_date + time_from_starting_date
print "Time:", result_date

Efficiency NSString vs NSInteger/int - only for textual representation

I'd like to know if it would make any sense to cast/convert a number, parsed from a csv file, e.g. customer id, to a NSString?
Or maybe better a simple int? As I'm quite new to obj-c, I'm not really sure, wether to consistently use the NSxyz types, or use what I'm used to, coming from Java/C/C++.
Actually the value only is stored in a variable, and then loaded into some textfields (which again would imply a conversion back to NSString I guess?).
Would there be any benefit in less memory being used? Let's assume the ids had 6 digits, parsing roughly 10'000-100'000 customers. Same would apply to smaller numbers, e.g. the addresses street number.
In a string, 1 letter == 1 byte, so if you have 6 digits, you are occupying 6 bytes.
An int instead takes generally 2 (short), 3 or 4 (long) bytes. It can arrive also to 8 bytes with an int_64. But, you are limited because for example in the 2 byte case (16 bit) you can consider 2^16 numbers.
In your case you could use an int, but i would use an NSString, also because you need it in your textfield.
An NSInteger is an int. An NSUInteger is an unsigned int.
An NSNumber is an Object (so no primitive) which can store an int, a float, a double or a boolean. So you can store many type of primitive in this type of variable and then use the appropriate:
[number floatValue];
[number boolValue];
...

Resources