在LINQ查询结果中格式化日期

8
以下 Linq to Entities 查询将给出以下结果:
public class UserCountResult
{
    public DateTime? date { get; set; } // **should this be string instead?**
    public int users { get; set; }
    public int visits { get; set; }
}

public JsonResult getActiveUserCount2(string from = "", string to = "")
{

    var query = from s in db.UserActions
                    group s by EntityFunctions.TruncateTime(s.Date) into g
                    select new UserCountResult
                    {
                        date = g.Key, // can't use .toString("dd.MM.yyyy") here
                        users = g.Select(x => x.User).Distinct().Count(),
                        visits = g.Where(x => x.Category == "online").Select(x => x.Category).Count()
                    };

    return Json(query, JsonRequestBehavior.AllowGet);

}

结果:

[{"date":"\/Date(1383433200000)\/","users":21,"visits":47},{"date":"\/Date(1383519600000)\/","users":91,"visits":236}]

我需要的日期格式是"dd.MM.yyyy",而不是像/Date(1383433200000)/这样的格式。

[{"date":"29.11.2013","users":21,"visits":47},{"date":"30.11.2013","users":91,"visits":236}]

我找不到在查询中修改格式的方法,也不确定该怎么做。我甚至不明白为什么g.Key是可空的。感谢任何意见!


我认为你应该能够使用 g.Key.GetValueOrDefault() - Rob Lyndon
1
你可以随时使用一些SqlFunctions,例如DatePart来提取日期的每个部分,然后将它们连接在一起以获得所需的格式。 - King King
在重新审视您的问题后,我注意到您代码中有些奇怪的地方,date 属性是 DateTime? 类型,但您仍然想将其赋值给某个字符串? - King King
4个回答

12

g.Key是可空的,因为这是EntityFunctions.TruncateTime的签名。 http://msdn.microsoft.com/en-us/library/dd395596.aspx.

要退出 Linq to Entities,您可以保留查询本身,并在事后对其进行投影:

return Json(query.AsEnumerable().Select(r => new 
    {
        date = r.date.GetValueOrDefault().ToString("dd.MM.yyyy"),
        users = r.users,
        visits = r.visits
    }), JsonRequestBehavior.AllowGet);

它并不美观,但这就是Linq to Entities的特点。


1
谢谢你的帮助。这在响应文本中给了我“'LINQ to Entities' 不认识方法 'System.String ToString(System.String)'”。 - peter
@peter 嗯,LINQ to Entity 总是抱怨很多 :), 这并不奇怪。 - King King
正如King King所说,Linq to Entities有些难以捉摸,但是有一个解决方法。待编辑。 - Rob Lyndon
1
这个解决方案意味着为了序列化的唯一目的而更改日期属性的类型... 如果您需要该类进行其他用途,则不是很方便。最干净的方法是更改序列化程序的行为。 - Thomas Levesque
我调整了投影,以便不返回新的UserCountResult,而只返回一个匿名类型((r=> new { .. } )),否则我必须像Thomas写的那样更改日期属性的类型。 - peter

4
假设您正在使用JSON.NET作为JSON序列化器,您可以将JsonConverterAttribute应用于date属性以指定自定义转换器。
[JsonConverter(typeof(MyDateConverter))]
public DateTime? date { get; set; }

你可以使用DateTimeConverterBase类作为转换器的基类。
下面是MyDateConverter的一个可能实现:
class CustomDateTimeConverter : DateTimeConverterBase
{
    private const string Format = "dd.MM.yyyy";

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        DateTime d = (DateTime)value;
        string s = d.ToString(Format);
        writer.WriteValue(s);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (s == null)
            return null;
        string s = (string)reader.Value;
        return DateTime.ParseExact(s, Format, null);
    }
}

另一个选择是从序列化中排除date属性(使用JsonIgnoreAttribute),并添加另一个类型为String的属性,该属性可转换为所需格式。以下是此解决方案的实现:
public class UserCountResult
{
    [JsonIgnore]
    public DateTime? date { get; set; }
    [JsonProperty("date")]
    public string DateAsString
    {
        get
        {
            return date != null ? date.Value.ToString("dd.MM.yyyy") : null;
        }
        set
        {
            date = string.IsNullOrEmpty(value) ? default(DateTime?) : DateTime.ParseExact(value, "dd.MM.yyyy", null);
        }
    }

    public int users { get; set; }
    public int visits { get; set; }
}

@elgonzo,不是的,它是ASP.NET MVC类型。但是如果我没记错的话,ASP.NET MVC使用JSON.NET作为其序列化器(或者至少可以配置为使用它)。 - Thomas Levesque
非常感谢您详细的回答,目前对于我的小需求来说似乎有些过于强大了,但我会深入研究这些主题。 - peter

3
如果使用SQL Server,您可以连接SQL函数的结果。
using System.Data.Entity.SqlServer;    

...

date = SqlFunctions.DatePart("year",g.Key)
    +"-"+SqlFunctions.DatePart("month",g.Key)
    +"-"+SqlFunctions.DatePart("day",g.Key)

2

类似这样的代码应该可以正常运行:

date = new Date(parseInt(g.Key.substr(6)));
substr函数会去掉"/Date("字符串,parseInt函数会提取整数,而Date函数则会给出一个新的日期对象。

编辑:

我找到了这个支持我的答案的SO问题。

如何格式化Microsoft JSON日期?


谢谢提供链接,不过我更希望从控制器中以我期望的格式返回数据。 - peter
@peter 在Scott Hanselman的博客上有很多有用的信息。 - crthompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接