ndb query error with datetime field - Google App Engine - google-app-engine

I'm having a problem and I don't find any information about.
I define a field in my model like this.
class Dates(ndb.model):
...
date = ndb.DateTimeProperty(required = True) # I want to store date and time
...
Later I try a query (now I want all the dates for a day, I don'tn mind the time):
kl = Dates.query(ndb.AND(Dates.date.year == year,
Dates.date.month == month,
Dates.date.day == day),
ancestor = customer.key).fetch(keys_only = True)
dates = ndb.get_multi(kl)
But I get this error log:
AttributeError: 'DateTimeProperty' object has no attribute 'year'
I don't know why. I've tried Dates.date() == date, Dates.date == date (<-DateTime obj), ...
My DB is still empty but I suppose this doesn't mind because I'll never have dates for every possible days.
Anybody knows why? Should I go with GQL instead?

You can use "range" queries for this. See example below.
import datetime
date = datetime.datetime.strptime('02/19/2013', '%m/%d/%Y')
kl = Dates.query(
ndb.AND(Dates.date >= date),
Dates.date < date + datetime.timedelta(days=1))
Will fetch all datetime's with 02/19/2013.

What you are trying to achieve is not really possible, because you can only query for the whole date and not for some parts of it.
In order to achieve what you are trying there I would suggest you to add few more properties to your model:
class Dates(ndb.model):
...
date = ndb.DateTimeProperty(requiered=True)
date_year = ndb.IntegerProperty()
date_month = ndb.IntegerProperty()
date_day = ndb.IntegerProperty()
...
You could update these values on every save or you could use Model Hooks to do it automagically and then your new query will become:
kl = Dates.query(ndb.AND(Dates.date_year == year,
Dates.date_month == month,
Dates.date_day == day),
ancestor=customer.key).fetch(keys_only=True)
dates = ndb.get_multi(kl)

Use a DateProperty. Then you can use a simple == query:
>>> import datetime
>>> from google.appengine.ext.ndb import *
>>> class D(Model):
... d = DateProperty()
...
>>> d = D(d=datetime.date.today())
>>> d.put()
Key('D', 9)
>>> d
D(key=Key('D', 9), d=datetime.date(2013, 2, 20))
>>> D.query(D.d == datetime.date.today()).fetch()
[D(key=Key('D', 9), d=datetime.date(2013, 2, 20))]

I expanded #Guido van Rossum code snippet to include <> and timedelta for calculations, mostly for my own satisfaction
import datetime
from datetime import timedelta
from google.appengine.ext.ndb import *
class D(Model):
d = DateProperty()
now = datetime.date.today()
date1 = now-timedelta(+500)
date2 = now-timedelta(+5)
d1 = D(d=now)
d2 = D(d=date1)
d3 = D(d=date2)
d1.put()
d2.put()
d3.put()
date2 = now-timedelta(+50)
result1 = D.query(D.d == now).fetch(4)
result2 = D.query(D.d > date2).fetch(2)
result3 = D.query(D.d < date2).fetch(2)
result4 = D.query(D.d >= date2, D.d <= now).fetch(2)
print result1
print "+++++++"
print result2
print "+++++++"
print result3
print "+++++++"
print result4

Related

How can I check in xarray if a coordinate exists?

I want something similar to this: if fileObj.is_file() == True: But for a dataset.
I want to check if a date exists befor I select it.
y_begin = 2007
y_end = 2020
begin_date = '05-01'
end_date = '09-31'
ds_so_merge = None
for y in range(y_begin, y_end +1):
begin = str(y) + '-' + begin_date
end = str(y) + '-' + end_date
!!!here checking if the date exists and if not trying the following date!!!
ds_so = dataset.sel(time=slice(begin, end))
if ds_so_merge is None:
ds_so_merge = ds_so
else:
ds_so_merge = ds_so.merge(ds_so_merge)
you can check if a coordinate contains a specific value with value in coord just like you could with a numpy array or a pandas index.
Another option since you're using slices would just be to pull all elements which match the slice criteria, then select the first matched element.
Something like the following should work:
first_time_matching_slice = dataset.sel(time=slice(begin, end)).isel(time=0)

Days count across the months with given start date and end date

I have a snippet of a table as below :
Can somebody help me with the query that gives me report as below:
If you don't want to use a calendar dimension as Mike suggested (which is a good idea) the best option may be a user defined table function (UDTF). This UDTF does not depend on the DAYS_COUNT column. It calculates the days in each month and only requires a start and end date. It will generate as many rows as are required to fill the months in between.
select * from a, table(DAYS_IN_MONTHS(START_DATE, END_DATE));
create or replace function DAYS_IN_MONTHS(START_DATE date, END_DATE date)
returns table(MONTHS string, DAYS float)
language javascript
strict immutable
as
$$
{
initialize: function (argumentInfo, context) {},
processRow: function (row, rowWriter, context) {
let year = row.START_DATE.getFullYear();
let month = row.START_DATE.getMonth();
let endYear = row.END_DATE.getFullYear();
let endMonth = row.END_DATE.getMonth();
let isDone = year > endYear || (year == endYear && month > endMonth);
if (year == endYear && month == endMonth) {
rowWriter.writeRow({MONTHS: `${year}-${(""+(month+1)).padStart(2, '0')}`,DAYS: row.END_DATE.getDate() - row.START_DATE.getDate()});
isDone = true;
}
d = row.START_DATE
while (!isDone) {
if (year == endYear && month == endMonth) {
rowWriter.writeRow({MONTHS: `${year}-${(""+(month+1)).padStart(2, '0')}`,DAYS: row.END_DATE.getDate() - (d.getDate() - 1) });
isDone = true;
} else {
rowWriter.writeRow({MONTHS: `${year}-${(""+(month+1)).padStart(2, '0')}`,DAYS: new Date(year, month + 1, 0).getDate() - (d.getDate() - 1) });
month++;
if (month == 12) {
month = 0;
year++;
}
}
d = new Date(year, month, 1);
}
},
finalize: function (rowWriter, context) {},
}
$$;
It would be very helpful if you'd have a calendar dimension for something like this. As an example, you can create one with something like this:
CREATE TEMP TABLE calendar AS
SELECT dateadd(day,seq4(),'2017-01-01'::date) as cal_date,
date_trunc(month,cal_date) as cal_month_start,
dateadd(day,-1,(dateadd(month,1, cal_month_start))) as cal_month_end
FROM table(generator(rowcount => 10000));
With this calendar table, you can then join to it using the start and end dates and aggregate on that date to get the results. Using a CTE to replicate your data:
WITH x AS (
SELECT member_id, start_date, end_date
FROM (VALUES ('461043068_02','2018-08-07'::date,'2018-08-17'::date),
('461043068_01','2019-05-28'::date,'2019-06-28'::date)
) y (member_id, start_date, end_date)
)
Now, you can query x and join to calendar as such:
SELECT member_id, cal_month_start, count(*)
FROM x
JOIN calendar c
ON c.cal_date between dateadd(day,1,x.start_date) and x.end_date
GROUP BY 1,2;
This gives you the results you are looking for. Please note the need to add 1 to the start_date, so that you don't count the "edges" of your date ranges twice.
Also, I didn't format the cal_month_start in my query, but you can do that using a TO_VARCHAR() function, if needed.

Strange results using dates in linq queries using EF Core

I'm getting strange results using trying to do a simple query against a date column using Linq and EF Core.
If I run the query using a date from a list of DateTime I get no results. If I substitute DateTime.Now and add a negative number of days so that if matches the date in the list of DateTimes then the query returns results as expected.
So what is the difference between DateTime.Now and another DateTime object?
In practice, why would this work (rewinding now by 30 days in the first example gives the same date as datesToCheck[0] in the second):
var reports = from r
in db.DailyReports
.Where(r => r.UserId.Equals(currentuser.Identity.Name)
&& r.Date > DateTime.Now.AddDays(-30))
select r;
But not this:
var reports = from r
in db.DailyReports
.Where(r => r.UserId.Equals(currentuser.Identity.Name)
&& r.Date > datesToCheck[0])
select r;
The database is SQL Server 2017, the column is a non-nullable smalldatetime
The datesToCheck list is generated thus:
var datesToCheck = new List<DateTime>();
var startDate = DateTime.Now;
//get Monday date three weeks ago
if (DateTime.Now.DayOfWeek != DayOfWeek.Monday)
{
while (startDate.DayOfWeek != DayOfWeek.Monday)
{
startDate = startDate.AddDays(-1);
}
}
startDate = startDate.AddDays(-21);
while (startDate < DateTime.Now)
{
if (startDate.DayOfWeek != DayOfWeek.Saturday || startDate.DayOfWeek != DayOfWeek.Sunday)
{
datesToCheck.Add(startDate);
startDate = startDate.AddDays(1);
}
}
The same behavior exists in EF6 and, as far as I know, all versions of EF. Basically, the compiler isn't clever enough to decide if datesToCheck[0] should be evaluated or converted to SQL. The query will work if you store the value in a variable and then use the variable in the LINQ query. See also: Why can't we use arrays in Entity Framework queries?
You probably have some datatype issue, Try:
DateTime datesToCheck = DateTime.Now.AddDays(-30);
var reports = from r
in db.DailyReports
.Where(r => r.UserId.Equals(currentuser.Identity.Name)
&& r.Date > datesToCheck )
select r;

Magento using operators in where clauses

My products have date_created and expires_in attributes. date_created is Magento date backend format while expires_in is a select that contains options as 1 week, 1 month etc.
Using those two attributes I'm trying to determine the total number of expired products. My idea was to write a query that selects:
products where date created + 1 week < now() AND expires_in = 1 week
AND
products where date created + 1 month < now() AND expires_in = 1 month
...
But I don't seem to be able to make even the first part of the first step to work:
$currentTimestamp = Mage::getModel('core/date')->timestamp(time());
$oneWeekTimestamp = Mage::getModel('core/date')->timestamp(strtotime("+1 week"));
$products = Mage::getResourceModel('catalog/product_collection')
->setStoreId(Mage::app()->getStore()->getId())
->addAttributeToSelect('')
...
//these are what i have tried so far:
$products->addAttributeToFilter('date_updated + ' . $oneWeekTimestamp , array('gt' => $currentTimestamp));
$products->addAttributeToFilter(new Zend_Db_Expr('date_updated + ' . $oneWeekTimestamp), array('gt' => $currentTimestamp));
$products->addAttributeToFilter("DATEDIFF($currentTimestamp, 'date_updated')" , array('gt' => 7));
$countExpired = $products -> count();
None of them seem to work. If possible I'd like the cross RDBMS solution.
You can do this in following way:
$currentTimestamp = Mage::getModel('core/date')->timestamp(time());
$oneWeekTimestamp = Mage::getModel('core/date')->timestamp(strtotime("+1 week"));
$oneweekDate=date("Y-m-d H:i:s",$oneWeekTimestamp);
$products->addAttributeToFilter('date_updated',array('date'=>true,'gt',$oneweekDate);

GQL SELECT Sorting

is there any easier way to select & sort by weight ?
fetchCount = 1000
date1 = datetime.datetime.utcnow().date()
entries = GqlQuery("SELECT * FROM Entry WHERE category = :category and date >= :datetime ORDER BY date, weight DESC", category = category, datetime = date1).fetch(fetchCount)
if entries is not None:
# Sort entries ( lazy way for now ).
sort = True
while sort:
sort = False
for i in range(0, len(entries)-1):
if entries[i].weight < entries[i + 1].weight:
e = entries[i + 1]
entries[i + 1] = entries[i]
entries[i] = e
sort = True
solved by:
entries = GqlQuery("SELECT * FROM Entry WHERE category = :category and date > :datetime ORDER BY date, weight DESC", category = category, datetime = date1).fetch(fetchCount)
entries = sorted(entries, key=lambda x: x.weight, reverse=True)
since there is no other way atm....
It's a limitation of the datastore that if you use an inequality filter (e.g. date >= :datetime) that must also be your first ordering key. Also, you can only have inequalities on one property per query. So, in your case you have no choice but sorting them in memory. The sorted() call in the other answer is perfect.

Resources