Unrecognized Edm.DateTime literal datetime – Como filtrar data no endpoint REST (OData) do Dynamics CRM 2011

O novo serviço REST fornecido a partir da versão 2011 do Microsoft Dynamics CRM, facilitou bastante as operações de CRUD (Create, Read, Update, Delete) nos JavaScripts.

Ficou muito mais fácil desenvolver e manter os scripts responsáveis por consumir e manipular os dados provindos do CRM, utilizando o “protocolo” OData (OrganizationData.svc).

Não vou entrar em detalhes sobre o assunto nesse post, pois, o intuito é solucionar uma dificuldade enfrentada na comparação de datas no parâmetro de filtro ($filter).

A documentação no MSDN indica que devemos utilizar uma data no formato UTC, e, nos fornece uma função que gera a data no formato supostamente correto:

function getODataUTCDateFilter(date) {
 
 var monthString;
 var rawMonth = (date.getUTCMonth()+1).toString();
 if (rawMonth.length == 1) {
  monthString = "0" + rawMonth;
 }
 else
 { monthString = rawMonth; }
 
 var dateString;
 var rawDate = date.getUTCDate().toString();
 if (rawDate.length == 1) {
  dateString = "0" + rawDate;
 }
 else
 { dateString = rawDate; }
 
 var DateFilter = "datetime'";
 DateFilter += date.getUTCFullYear() + "-";
 DateFilter += monthString + "-";
 DateFilter += dateString;
 DateFilter += "T" + date.getUTCHours() + ":";
 DateFilter += date.getUTCMinutes() + ":";
 DateFilter += date.getUTCSeconds() + ":";
 DateFilter += date.getUTCMilliseconds();
 DateFilter += "Z'";
 return DateFilter;
}


Entretanto, utilizando essa função, o serviço nos retorna um erro, informando que a data transmitida está em um formato inválido: Unrecognized ‘Edm.DateTime’ literal ‘datetime’2011-11-14T16:43:8Z” in ’75′.

Analisando melhor, entendemos que essa função está errada e que a mesma só funcionará em determinados cenários.
A data, hora, minuto e segundo sempre precisam estar com 2 casas (00) e o valor não deve possuir os milissegundos, logo a função não atende.

Corrigimos e adaptamos essa função para gerar datas no formato esperado pelo serviço OData nos critérios de filtro.

A função foi adaptada para um protótipo da classe Date:

Date.prototype.toCRMFormatDateFilter = function () {
    var date = this;
    var monthString;
    var rawMonth = (date.getUTCMonth() + 1).toString();
    if (rawMonth.length == 1) {
        monthString = "0" + rawMonth;
    }
    else
    { monthString = rawMonth; }
 
    var dateString;
    var rawDate = date.getUTCDate().toString();
    if (rawDate.length == 1) {
        dateString = "0" + rawDate;
    }
    else
    { dateString = rawDate; }
 
    var horasString = date.getUTCHours().toString();
    if (horasString.length == 1)
        horasString = "0" + horasString;
 
    var minutosString = date.getUTCMinutes().toString();
    if (minutosString.length == 1)
        minutosString = "0" + minutosString;
 
    var segundosString = date.getUTCSeconds().toString();
    if (segundosString.length == 1)
        segundosString = "0" + segundosString;
 
    var DateFilter = "datetime'";
    DateFilter += date.getUTCFullYear() + "-";
    DateFilter += monthString + "-";
    DateFilter += dateString;
    DateFilter += "T" + horasString + ":";
    DateFilter += minutosString + ":";
    DateFilter += segundosString + "Z'";
    return DateFilter;
}


Para utilizar é simples:

var data = new Date();
var dataUtcFilter = data.toCRMFormatDateFilter();
 
// dataUtcFilter = datetime'2011-11-14T19:35:34Z'


A partir de agora o valor já pode ser utilizado para comparar data.

Exemplo:


Vamos solicitar todos os itens da fila que foram criados antes ou na data/hora usada anteriormente, ordenando pelo título e restringindo o resultado a 5 registros.

http://crm.virtualgroup.com.br/Organizacao/XRMServices/2011/OrganizationData.svc/QueueItemSet?$filter=CreatedOn le datetime'2011-11-14T19:35:34Z'&$orderby=Title&$top=5